blob: fed084e3a9cfb63b5669222a1a397cb2766467a6 [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
Sadik Armagan32ca1442020-11-13 17:51:56 +00008#include "DelegateUtils.hpp"
9
Sadik Armagan62483be2020-10-23 17:14:43 +010010#include <tensorflow/lite/builtin_ops.h>
11#include <tensorflow/lite/c/builtin_op_data.h>
12#include <tensorflow/lite/c/common.h>
13#include <tensorflow/lite/minimal_logging.h>
Sadik Armagan32ca1442020-11-13 17:51:56 +000014#include "tensorflow/lite/kernels/internal/tensor.h"
Sadik Armagan62483be2020-10-23 17:14:43 +010015
16namespace armnnDelegate
17{
18
Sadik Armagan32ca1442020-11-13 17:51:56 +000019TfLiteStatus VisitConv2dOperator(DelegateData& delegateData,
20 TfLiteContext* tfLiteContext,
21 TfLiteNode* tfLiteNode,
22 int nodeIndex,
23 int32_t operatorCode)
24{
25 auto numInputs = tfLiteNode->inputs->size;
26 if (numInputs < 2)
27 {
28 TF_LITE_MAYBE_KERNEL_LOG(
29 tfLiteContext, "TfLiteArmnnDelegate: Minimum number of inputs (%d != %d) in node #%d",
30 2, numInputs, nodeIndex);
31 return kTfLiteError;
32 }
33 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
34
35 armnn::Convolution2dDescriptor descriptor;
36 const auto params = reinterpret_cast<TfLiteConvParams*>(tfLiteNode->builtin_data);
37
38 bool biasEnabled = tfLiteNode->inputs->size > 2;
39 descriptor.m_BiasEnabled = biasEnabled;
40 descriptor.m_StrideX = NonNegative(params->stride_width, nodeIndex);
41 descriptor.m_StrideY = NonNegative(params->stride_height, nodeIndex);
42 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
43 descriptor.m_DilationX = NonNegative(params->dilation_width_factor, nodeIndex);
44 descriptor.m_DilationY = NonNegative(params->dilation_height_factor, nodeIndex);
45
46 const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors;
47 const TfLiteTensor& tfLiteInputTensor = tfLiteTensors[tfLiteNode->inputs->data[0]];
48 if(!IsValid(&tfLiteTensors[tfLiteNode->inputs->data[0]]))
49 {
50 TF_LITE_MAYBE_KERNEL_LOG(
51 tfLiteContext,
52 "TfLiteArmnnDelegate: Invalid input tensor in operator #%d node #%d: ",
53 operatorCode, nodeIndex);
54 return kTfLiteError;
55 }
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 operatorCode, nodeIndex);
62 return kTfLiteError;
63 }
64 const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]];
65 if(!IsValid(&tfLiteOutputTensor))
66 {
67 TF_LITE_MAYBE_KERNEL_LOG(
68 tfLiteContext,
69 "TfLiteArmnnDelegate: Invalid output tensor in operator #%d node #%d: ",
70 operatorCode, nodeIndex);
71 return kTfLiteError;
72 }
73 if (IsDynamicTensor(tfLiteOutputTensor))
74 {
75 TF_LITE_MAYBE_KERNEL_LOG(
76 tfLiteContext,
77 "TfLiteArmnnDelegate: Dynamic output tensors are not supported in operator #%d node #%d: ",
78 operatorCode, nodeIndex);
79 return kTfLiteError;
80 }
81
82 const TfLiteTensor& tfLiteFilterTensor = tfLiteTensors[tfLiteNode->inputs->data[1]];
83 if(!IsValid(&tfLiteFilterTensor))
84 {
85 TF_LITE_MAYBE_KERNEL_LOG(
86 tfLiteContext,
87 "TfLiteArmnnDelegate: Invalid filter tensor in operator #%d node #%d: ",
88 operatorCode, nodeIndex);
89 return kTfLiteError;
90 }
91 if (IsDynamicTensor(tfLiteFilterTensor))
92 {
93 TF_LITE_MAYBE_KERNEL_LOG(
94 tfLiteContext,
95 "TfLiteArmnnDelegate: Dynamic filter tensors are not supported in node #%d: ",
96 nodeIndex);
97 return kTfLiteError;
98 }
99
100 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteInputTensor);
101 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor);
102
103 armnn::TensorInfo filterTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteFilterTensor);
104
105 armnn::TensorInfo biasTensorInfo;
106 if(biasEnabled)
107 {
108 const TfLiteTensor& tfLiteBiasTensor = tfLiteTensors[tfLiteNode->inputs->data[2]];
109 if(!IsValid(&tfLiteBiasTensor))
110 {
111 TF_LITE_MAYBE_KERNEL_LOG(
112 tfLiteContext,
113 "TfLiteArmnnDelegate: Invalid bias tensor in operator #%d node #%d: ",
114 operatorCode, nodeIndex);
115 return kTfLiteError;
116 }
117 if (IsDynamicTensor(tfLiteBiasTensor))
118 {
119 TF_LITE_MAYBE_KERNEL_LOG(
120 tfLiteContext,
121 "TfLiteArmnnDelegate: Dynamic bias tensors are not supported in node #%d: ",
122 nodeIndex);
123 return kTfLiteError;
124 }
125 biasTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteBiasTensor);
126 }
127 else
128 {
129 biasTensorInfo = armnn::TensorInfo(armnn::TensorShape({1}), GetDataType(tfLiteInputTensor));
130 }
131
132 armnn::Optional<armnn::TensorInfo> optionalBiasInfo(biasTensorInfo);
133
134 // TfLite uses NHWC tensors
135 const unsigned int inputHeight = inputTensorInfo.GetShape()[1];
136 const unsigned int inputWidth = inputTensorInfo.GetShape()[2];
137
138 const unsigned int filterHeight = filterTensorInfo.GetShape()[1];
139 const unsigned int filterWidth = filterTensorInfo.GetShape()[2];
140
141 // Calculate padding
142 CalcPadding(inputHeight, filterHeight, descriptor.m_StrideY, descriptor.m_DilationY,
143 descriptor.m_PadTop, descriptor.m_PadBottom, params->padding);
144 CalcPadding(inputWidth, filterWidth, descriptor.m_StrideX, descriptor.m_DilationX,
145 descriptor.m_PadLeft, descriptor.m_PadRight, params->padding);
146
147 if (!delegateData.m_Network)
148 {
149 bool isSupported = false;
150 FORWARD_LAYER_SUPPORT_FUNC(__func__,
151 tfLiteContext,
152 IsConvolution2dSupported,
153 delegateData.m_Backends,
154 isSupported,
155 inputTensorInfo,
156 outputTensorInfo,
157 descriptor,
158 filterTensorInfo,
159 optionalBiasInfo);
160 return isSupported ? kTfLiteOk : kTfLiteError;
161 }
162
163 armnn::IConnectableLayer* layer = nullptr;
164
165 // Set up filter and biases
166 auto filter =
167 CreateConstTensor(&tfLiteContext->tensors[tfLiteNode->inputs->data[1]],
168 filterTensorInfo,
169 armnn::Optional<armnn::PermutationVector&>());
170
171 if(biasEnabled)
172 {
173 auto biases =
174 CreateConstTensor(&tfLiteContext->tensors[tfLiteNode->inputs->data[2]],
175 biasTensorInfo,
176 armnn::Optional<armnn::PermutationVector&>());
177 layer = delegateData.m_Network->AddConvolution2dLayer(descriptor,
178 filter,
179 armnn::Optional<armnn::ConstTensor>(biases));
180 }
181 else
182 {
183 layer = delegateData.m_Network->AddConvolution2dLayer(descriptor,
184 filter,
185 armnn::EmptyOptional());
186 }
187
188 ARMNN_ASSERT(layer != nullptr);
189
190 armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(0);
191 outputSlot.SetTensorInfo(outputTensorInfo);
192
193 Connect(layer, tfLiteNode, delegateData);
194
195 auto* tfLiteNodeParameters = reinterpret_cast<TfLiteConvParams*>(tfLiteNode->builtin_data);
196 if (!tfLiteNodeParameters)
197 {
198 // No Activation
199 return kTfLiteOk;
200 }
201 // Check activation
202 TfLiteFusedActivation activationType = tfLiteNodeParameters->activation;
203 return FusedActivation(tfLiteContext, tfLiteNode, activationType, layer, 0, delegateData);
204
205}
206
207TfLiteStatus VisitDepthwiseConv2dOperator(DelegateData& delegateData,
208 TfLiteContext* tfLiteContext,
209 TfLiteNode* tfLiteNode,
210 int nodeIndex,
211 int32_t operatorCode)
212{
213 auto numInputs = tfLiteNode->inputs->size;
214 if (numInputs < 2)
215 {
216 TF_LITE_MAYBE_KERNEL_LOG(
217 tfLiteContext, "TfLiteArmnnDelegate: Minimum number of inputs (%d != %d) in node #%d",
218 2, numInputs, nodeIndex);
219 return kTfLiteError;
220 }
221 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
222
223 bool biasEnabled = tfLiteNode->inputs->size > 2;
224
225 armnn::DepthwiseConvolution2dDescriptor descriptor;
226 const auto params = reinterpret_cast<TfLiteDepthwiseConvParams*>(tfLiteNode->builtin_data);
227
228 descriptor.m_BiasEnabled = biasEnabled;
229 descriptor.m_StrideX = NonNegative(params->stride_width, nodeIndex);
230 descriptor.m_StrideY = NonNegative(params->stride_height, nodeIndex);
231 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
232 descriptor.m_DilationX = NonNegative(params->dilation_width_factor, nodeIndex);
233 descriptor.m_DilationY = NonNegative(params->dilation_height_factor, nodeIndex);
234
235 const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors;
236 const TfLiteTensor& tfLiteInputTensor = tfLiteTensors[tfLiteNode->inputs->data[0]];
237 if(!IsValid(&tfLiteInputTensor))
238 {
239 TF_LITE_MAYBE_KERNEL_LOG(
240 tfLiteContext,
241 "TfLiteArmnnDelegate: Invalid input tensor in operator #%d node #%d: ",
242 operatorCode, nodeIndex);
243 return kTfLiteError;
244 }
245 if (IsDynamicTensor(tfLiteInputTensor))
246 {
247 TF_LITE_MAYBE_KERNEL_LOG(
248 tfLiteContext,
249 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
250 operatorCode, nodeIndex);
251 return kTfLiteError;
252 }
253 const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]];
254 if(!IsValid(&tfLiteOutputTensor))
255 {
256 TF_LITE_MAYBE_KERNEL_LOG(
257 tfLiteContext,
258 "TfLiteArmnnDelegate: Invalid output tensor in operator #%d node #%d: ",
259 operatorCode, nodeIndex);
260 return kTfLiteError;
261 }
262 if (IsDynamicTensor(tfLiteOutputTensor))
263 {
264 TF_LITE_MAYBE_KERNEL_LOG(
265 tfLiteContext,
266 "TfLiteArmnnDelegate: Dynamic output tensors are not supported in operator #%d node #%d: ",
267 operatorCode, nodeIndex);
268 return kTfLiteError;
269 }
270
271 const TfLiteTensor& tfLiteFilterTensor = tfLiteTensors[tfLiteNode->inputs->data[1]];
272 if(!IsValid(&tfLiteFilterTensor))
273 {
274 TF_LITE_MAYBE_KERNEL_LOG(
275 tfLiteContext,
276 "TfLiteArmnnDelegate: Invalid filter tensor in operator #%d node #%d: ",
277 operatorCode, nodeIndex);
278 return kTfLiteError;
279 }
280 if (IsDynamicTensor(tfLiteFilterTensor))
281 {
282 TF_LITE_MAYBE_KERNEL_LOG(
283 tfLiteContext,
284 "TfLiteArmnnDelegate: Dynamic filter tensors are not supported in node #%d: ",
285 nodeIndex);
286 return kTfLiteError;
287 }
288
289 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteInputTensor);
290 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor);
291
292 // Mappings from TensorflowLite filter tensors to the ArmNN filter tensors (ArmNN weights have to be [M, I, H, W])
293 armnn::PermutationVector permutationVector{ 2, 3, 1, 0 }; // [H, W, I, M] -> [M, I, H, W]
294 armnn::TensorInfo filterTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteFilterTensor, permutationVector);
295
296 // Assuming input is NHWC
297 unsigned int inputHeight = inputTensorInfo.GetShape()[1];
298 unsigned int inputWidth = inputTensorInfo.GetShape()[2];
299
300 // TensorflowLite weights come in the format [1, H, W, I * M]
301 unsigned int filterHeight = filterTensorInfo.GetShape()[1];
302 unsigned int filterWidth = filterTensorInfo.GetShape()[2];
303
304 // Reshape weights as [ H, W, I, M ]
305 filterTensorInfo.SetShape({ filterHeight,
306 filterWidth,
307 inputTensorInfo.GetShape()[3],
308 filterTensorInfo.GetShape()[3] / inputTensorInfo.GetShape()[3] });
309
310 // Calculate padding
311 CalcPadding(inputHeight, filterHeight, descriptor.m_StrideY, descriptor.m_DilationY,
312 descriptor.m_PadTop, descriptor.m_PadBottom, params->padding);
313 CalcPadding(inputWidth, filterWidth, descriptor.m_StrideX, descriptor.m_DilationX,
314 descriptor.m_PadLeft, descriptor.m_PadRight, params->padding);
315
316 armnn::TensorInfo biasTensorInfo;
317 if(biasEnabled)
318 {
319 const TfLiteTensor& tfLiteBiasTensor = tfLiteTensors[tfLiteNode->inputs->data[2]];
320 if(!IsValid(&tfLiteBiasTensor))
321 {
322 TF_LITE_MAYBE_KERNEL_LOG(
323 tfLiteContext,
324 "TfLiteArmnnDelegate: Invalid bias tensor in operator #%d node #%d: ",
325 operatorCode, nodeIndex);
326 return kTfLiteError;
327 }
328 if (IsDynamicTensor(tfLiteBiasTensor))
329 {
330 TF_LITE_MAYBE_KERNEL_LOG(
331 tfLiteContext,
332 "TfLiteArmnnDelegate: Dynamic bias tensors are not supported in node #%d: ",
333 nodeIndex);
334 return kTfLiteError;
335 }
336 biasTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteBiasTensor);
337 }
338 else
339 {
340 biasTensorInfo = armnn::TensorInfo(armnn::TensorShape({1}), GetDataType(tfLiteInputTensor));
341 }
342
343 if (!delegateData.m_Network)
344 {
345 bool isSupported = false;
346 FORWARD_LAYER_SUPPORT_FUNC(__func__,
347 tfLiteContext,
348 IsDepthwiseConvolutionSupported,
349 delegateData.m_Backends,
350 isSupported,
351 inputTensorInfo,
352 outputTensorInfo,
353 descriptor,
354 filterTensorInfo,
355 armnn::Optional<armnn::TensorInfo>(biasTensorInfo));
356 return isSupported ? kTfLiteOk : kTfLiteError;
357 }
358
359 armnn::IConnectableLayer* layer = nullptr;
360 std::vector<uint8_t> swizzledData(filterTensorInfo.GetNumBytes());
361 auto filter =
362 CreateConstTensor(&tfLiteFilterTensor,
363 filterTensorInfo,
364 armnn::Optional<armnn::PermutationVector&>(permutationVector),
365 swizzledData.data());
366 if(biasEnabled)
367 {
368 auto biases =
369 CreateConstTensor(&tfLiteContext->tensors[tfLiteNode->inputs->data[2]],
370 biasTensorInfo,
371 armnn::Optional<armnn::PermutationVector&>());
372 layer = delegateData.m_Network->AddDepthwiseConvolution2dLayer(descriptor,
373 filter,
374 armnn::Optional<armnn::ConstTensor>(biases));
375 }
376 else
377 {
378 layer = delegateData.m_Network->AddDepthwiseConvolution2dLayer(descriptor,
379 filter,
380 armnn::EmptyOptional());
381 }
382
383 ARMNN_ASSERT(layer != nullptr);
384
385 armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(0);
386 outputSlot.SetTensorInfo(outputTensorInfo);
387
388 Connect(layer, tfLiteNode, delegateData);
389 auto* tfLiteNodeParameters = reinterpret_cast<TfLiteDepthwiseConvParams*>(tfLiteNode->builtin_data);
390 if (!tfLiteNodeParameters)
391 {
392 // No Activation
393 return kTfLiteOk;
394 }
395 // Check activation
396 TfLiteFusedActivation activationType = tfLiteNodeParameters->activation;
397 return FusedActivation(tfLiteContext, tfLiteNode, activationType, layer, 0, delegateData);
398}
399
400TfLiteStatus VisitTransposeConv2dOperator(DelegateData& delegateData,
401 TfLiteContext* tfLiteContext,
402 TfLiteNode* tfLiteNode,
403 int nodeIndex,
404 int32_t operatorCode)
405{
406 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 3, nodeIndex));
407 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
408
409 armnn::TransposeConvolution2dDescriptor descriptor;
410 auto* parameters = reinterpret_cast<TfLiteTransposeConvParams*>(tfLiteNode->builtin_data);
411 descriptor.m_BiasEnabled = false;
412 descriptor.m_StrideX = NonNegative(parameters->stride_width, nodeIndex);
413 descriptor.m_StrideY = NonNegative(parameters->stride_height, nodeIndex);
414 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
415
416 const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors;
417 const TfLiteTensor& tfLiteOutputShapeTensor = tfLiteTensors[tfLiteNode->inputs->data[0]];
418 if(!IsValid(&tfLiteOutputShapeTensor))
419 {
420 TF_LITE_MAYBE_KERNEL_LOG(
421 tfLiteContext,
422 "TfLiteArmnnDelegate: Invalid input tensor in operator #%d node #%d: ",
423 operatorCode, nodeIndex);
424 return kTfLiteError;
425 }
426 if (IsDynamicTensor(tfLiteOutputShapeTensor))
427 {
428 TF_LITE_MAYBE_KERNEL_LOG(
429 tfLiteContext,
430 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
431 operatorCode, nodeIndex);
432 return kTfLiteError;
433 }
434
435 armnn::TensorInfo tensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputShapeTensor);
436 std::vector<int32_t> outputShape(tensorInfo.GetNumElements());
437 if (tensorInfo.GetDataType() == armnn::DataType::Signed32)
438 {
439 for(unsigned int i=0; i < tensorInfo.GetNumElements(); i++)
440 {
441 outputShape[i] = ::tflite::GetTensorData<int32_t>(&tfLiteOutputShapeTensor)[i];
442 }
443 }
444
445 if (tensorInfo.GetDataType() == armnn::DataType::QAsymmU8)
446 {
447 for(unsigned int i=0; i < tensorInfo.GetNumElements(); i++)
448 {
449 outputShape[i] = ::tflite::GetTensorData<uint8_t>(&tfLiteOutputShapeTensor)[i];
450 }
451 }
452 // Change from signed to unsigned int to store in TransposeConvolution2dDescriptor.
453 for (int dimension : outputShape)
454 {
455 descriptor.m_OutputShape.push_back(static_cast<unsigned int>(dimension));
456 }
457 descriptor.m_OutputShapeEnabled = true;
458
459 const TfLiteTensor& tfLiteInputTensor = tfLiteTensors[tfLiteNode->inputs->data[2]];
460 if(!IsValid(&tfLiteInputTensor))
461 {
462 TF_LITE_MAYBE_KERNEL_LOG(
463 tfLiteContext,
464 "TfLiteArmnnDelegate: Invalid input tensor in operator #%d node #%d: ",
465 operatorCode, nodeIndex);
466 return kTfLiteError;
467 }
468 if (IsDynamicTensor(tfLiteInputTensor))
469 {
470 TF_LITE_MAYBE_KERNEL_LOG(
471 tfLiteContext,
472 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
473 operatorCode, nodeIndex);
474 return kTfLiteError;
475 }
476
477 const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]];
478 if(!IsValid(&tfLiteOutputTensor))
479 {
480 TF_LITE_MAYBE_KERNEL_LOG(
481 tfLiteContext,
482 "TfLiteArmnnDelegate: Invalid output tensor in operator #%d node #%d: ",
483 operatorCode, nodeIndex);
484 return kTfLiteError;
485 }
486 if (IsDynamicTensor(tfLiteOutputTensor))
487 {
488 TF_LITE_MAYBE_KERNEL_LOG(
489 tfLiteContext,
490 "TfLiteArmnnDelegate: Dynamic output tensors are not supported in operator #%d node #%d: ",
491 operatorCode, nodeIndex);
492 return kTfLiteError;
493 }
494
495 const TfLiteTensor& tfLiteFilterTensor = tfLiteTensors[tfLiteNode->inputs->data[1]];
496 if(!IsValid(&tfLiteFilterTensor))
497 {
498 TF_LITE_MAYBE_KERNEL_LOG(
499 tfLiteContext,
500 "TfLiteArmnnDelegate: Invalid filter tensor in operator #%d node #%d: ",
501 operatorCode, nodeIndex);
502 return kTfLiteError;
503 }
504 if (IsDynamicTensor(tfLiteFilterTensor))
505 {
506 TF_LITE_MAYBE_KERNEL_LOG(
507 tfLiteContext,
508 "TfLiteArmnnDelegate: Dynamic filter tensors are not supported in operator #%d node #%d: ",
509 operatorCode, nodeIndex);
510 return kTfLiteError;
511 }
512
513 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteInputTensor);
514 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor);
515 armnn::TensorInfo filterTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteFilterTensor);
516
517 // TfLite uses NHWC tensors
518 const unsigned int inputHeight = inputTensorInfo.GetShape()[1];
519 const unsigned int inputWidth = inputTensorInfo.GetShape()[2];
520
521 const unsigned int filterHeight = filterTensorInfo.GetShape()[1];
522 const unsigned int filterWidth = filterTensorInfo.GetShape()[2];
523
524 // Calculate padding
525 CalcPadding(inputHeight,
526 filterHeight,
527 descriptor.m_StrideY,
528 1, // dilation y
529 descriptor.m_PadTop,
530 descriptor.m_PadBottom,
531 parameters->padding);
532 CalcPadding(inputWidth,
533 filterWidth,
534 descriptor.m_StrideX,
535 1, // dilation x
536 descriptor.m_PadLeft,
537 descriptor.m_PadRight,
538 parameters->padding);
539
540 // Set up filter
541 auto filterTensor = CreateConstTensor(&tfLiteFilterTensor,
542 filterTensorInfo,
543 armnn::Optional<armnn::PermutationVector&>());
544 if (!delegateData.m_Network)
545 {
546 bool isSupported = false;
547 FORWARD_LAYER_SUPPORT_FUNC(__func__,
548 tfLiteContext,
549 IsTransposeConvolution2dSupported,
550 delegateData.m_Backends,
551 isSupported,
552 inputTensorInfo,
553 outputTensorInfo,
554 descriptor,
555 filterTensorInfo,
556 armnn::EmptyOptional());
557 return isSupported ? kTfLiteOk : kTfLiteError;
558 }
559
560 armnn::IConnectableLayer* layer = delegateData.m_Network->AddTransposeConvolution2dLayer(descriptor,
561 filterTensor,
562 armnn::EmptyOptional());
563 ARMNN_ASSERT(layer != nullptr);
564
565 armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(0);
566 outputSlot.SetTensorInfo(outputTensorInfo);
567
568 // Connect
569 if (delegateData.m_OutputSlotForNode[tfLiteNode->inputs->data[2]] != nullptr)
570 {
571 delegateData.m_OutputSlotForNode[tfLiteNode->inputs->data[2]]->Connect(layer->GetInputSlot(0));
572 }
573
574 // Prepare output slots
575 for (unsigned int outputIndex = 0; outputIndex < layer->GetNumOutputSlots(); ++outputIndex)
576 {
577 armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(outputIndex);
578 delegateData.m_OutputSlotForNode[tfLiteNode->outputs->data[outputIndex]] = &outputSlot;
579 }
580 return kTfLiteOk;
581}
582
Sadik Armagan62483be2020-10-23 17:14:43 +0100583TfLiteStatus VisitConvolutionOperator(DelegateData& delegateData,
584 TfLiteContext* tfLiteContext,
585 TfLiteNode* tfLiteNode,
586 int nodeIndex,
587 int32_t operatorCode)
588{
Sadik Armagan32ca1442020-11-13 17:51:56 +0000589 switch(operatorCode)
590 {
591 case kTfLiteBuiltinConv2d:
592 return VisitConv2dOperator(delegateData, tfLiteContext, tfLiteNode, nodeIndex, operatorCode);
593 case kTfLiteBuiltinDepthwiseConv2d:
594 return VisitDepthwiseConv2dOperator(delegateData, tfLiteContext, tfLiteNode, nodeIndex, operatorCode);
595 case kTfLiteBuiltinTransposeConv:
596 return VisitTransposeConv2dOperator(delegateData, tfLiteContext, tfLiteNode, nodeIndex, operatorCode);
597 default:
598 return kTfLiteError;
599 }
Sadik Armagan62483be2020-10-23 17:14:43 +0100600}
601
602} // namespace armnnDelegate