blob: d49d20b5c10418e6177099bb64f4516a2cb7885d [file] [log] [blame]
Tracy Narine7306bbe2023-07-17 16:06:26 +01001//
2// Copyright © 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
12#include <tensorflow/lite/builtin_ops.h>
13#include <tensorflow/lite/c/builtin_op_data.h>
14#include <tensorflow/lite/c/common.h>
15#include <tensorflow/lite/minimal_logging.h>
16#include <tensorflow/lite/kernels/internal/tensor_ctypes.h>
17
18namespace armnnDelegate
19{
20
21
22
23TfLiteStatus ValidateReverseV2Operator(DelegateData& delegateData,
24 TfLiteContext* tfLiteContext,
25 const armnn::TensorInfo& inputInfo0,
26 const armnn::TensorInfo& inputInfo1,
27 const armnn::TensorInfo& outputInfo)
28{
29 bool isSupported = false;
30 FORWARD_LAYER_SUPPORT_FUNC("REVERSEV2",
31 tfLiteContext,
32 IsReverseV2Supported,
33 delegateData.m_Backends,
34 isSupported,
35 armnn::BackendId(),
36 inputInfo0,
37 inputInfo1,
38 outputInfo);
39
40 return isSupported ? kTfLiteOk : kTfLiteError;
41}
42
43TfLiteStatus VisitReverseV2Operator(DelegateData& delegateData,
44 TfLiteContext* tfLiteContext,
45 TfLiteNode* tfLiteNode,
46 int nodeIndex,
47 int32_t reverseV2OperatorCode)
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 that should be reversed
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 reverseV2OperatorCode, nodeIndex);
62 return kTfLiteError;
63 }
64
65 // The second input contains an axis tensor.
66 const TfLiteTensor& tfLiteAxisTensor = tfLiteTensors[tfLiteNode->inputs->data[1]];
67 if (IsDynamicTensor(tfLiteAxisTensor))
68 {
69 TF_LITE_MAYBE_KERNEL_LOG(
70 tfLiteContext,
71 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
72 reverseV2OperatorCode, nodeIndex);
73 return kTfLiteError;
74 }
75
76 // Get the output tensor
77 const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]];
78 if (IsDynamicTensor(tfLiteOutputTensor))
79 {
80 TF_LITE_MAYBE_KERNEL_LOG(
81 tfLiteContext,
82 "TfLiteArmnnDelegate: Dynamic output tensors are not supported in operator #%d node #%d: ",
83 reverseV2OperatorCode, nodeIndex);
84 return kTfLiteError;
85 }
86
87 const armnn::TensorInfo& inputTensorInfo0 = GetTensorInfoForTfLiteTensor(tfLiteInputTensor);
88 const armnn::TensorInfo& inputTensorInfo1 = GetTensorInfoForTfLiteTensor(tfLiteAxisTensor);
89 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true);
90
91 if (inputTensorInfo0.GetNumDimensions() != outputTensorInfo.GetNumDimensions())
92 {
93 TF_LITE_MAYBE_KERNEL_LOG(
94 tfLiteContext,
95 "TfLiteArmnnDelegate: input tensor dimension and output tensor dimension differ #%d node #%d: ",
96 reverseV2OperatorCode, nodeIndex);
97 return kTfLiteError;
98 }
99
100 for (unsigned i=0; i < inputTensorInfo0.GetNumDimensions(); i++)
101 {
102 if (inputTensorInfo0.GetShape()[i] != outputTensorInfo.GetShape()[i])
103 {
104 TF_LITE_MAYBE_KERNEL_LOG(
105 tfLiteContext,
106 "TfLiteArmnnDelegate: input tensor dimension and output tensor differ #%d node #%d: ",
107 reverseV2OperatorCode, nodeIndex);
108 return kTfLiteError;
109 }
110 }
111
112 std::string layerName("ReverseV2");
113
114 const auto maxDimension = 4;
115
116 const auto axisTensorNumValues = static_cast<unsigned int>(tfLiteAxisTensor.dims->size);
117 if (axisTensorNumValues > maxDimension)
118 {
119 TF_LITE_MAYBE_KERNEL_LOG(
120 tfLiteContext,
121 "TfLiteArmnnDelegate: The Axis-Input-Tensor of the ReverseV2 operation requires a "
122 "dimension of <= %d but a tensor with a dimension of %d was given. "
123 "Operator: #%d node #%d: ",
124 maxDimension, axisTensorNumValues, reverseV2OperatorCode, nodeIndex);
125 return kTfLiteError;
126 }
127
128 // No network pointer indicates that only support for this operator should be checked
129 if (!delegateData.m_Network)
130 {
131 return ValidateReverseV2Operator(delegateData,
132 tfLiteContext,
133 inputTensorInfo0,
134 inputTensorInfo1,
135 outputTensorInfo);
136 }
137
138 armnn::IConnectableLayer* reverseV2Layer = delegateData.m_Network->AddReverseV2Layer(layerName.c_str());
139
140 armnn::IOutputSlot& outputSlot = reverseV2Layer->GetOutputSlot(0);
141 outputSlot.SetTensorInfo(outputTensorInfo);
142
143 // Try to connect the Constant Inputs if there are any
144 if(ProcessInputs(reverseV2Layer, delegateData, tfLiteContext, tfLiteNode) != kTfLiteOk )
145 {
146 return kTfLiteError;
147 }
148
149 ARMNN_ASSERT(reverseV2Layer != nullptr);
150
151 return Connect(reverseV2Layer, tfLiteNode, delegateData);
152}
153
154} // namespace armnnDelegate