blob: 9a63e43afc872f38a680376058b13b9a2326406a [file] [log] [blame]
Sadik Armagan62483be2020-10-23 17:14:43 +01001//
Ryan OShea4c231de2023-01-17 15:19:20 +00002// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
Sadik Armagan62483be2020-10-23 17:14:43 +01003// SPDX-License-Identifier: MIT
4//
5
6#pragma once
7
Finn Williams6f9f9902020-11-13 13:23:15 +00008#include <armnn/utility/IgnoreUnused.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>
Mike Kelly04f71202023-05-05 15:35:18 +010014#include <fmt/format.h>
Sadik Armagan62483be2020-10-23 17:14:43 +010015
16namespace armnnDelegate
17{
18
19TfLiteStatus VisitSliceOperator(DelegateData& delegateData,
20 TfLiteContext* tfLiteContext,
21 TfLiteNode* tfLiteNode,
22 int nodeIndex,
23 int32_t sliceOperatorCode)
24{
Cathal Corbett839b9322022-11-18 08:52:18 +000025 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 3, nodeIndex));
Jan Eilers2ffddda2021-02-03 09:14:30 +000026 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
Finn Williams6f9f9902020-11-13 13:23:15 +000027
Cathal Corbett839b9322022-11-18 08:52:18 +000028 // Read inputs [input, begin, size]
Jan Eilers2ffddda2021-02-03 09:14:30 +000029 int numInputs = tfLiteNode->inputs->size;
30 std::vector<const TfLiteTensor*> tfLiteInputs;
31 tfLiteInputs.reserve(numInputs);
32 const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors;
33 for (int i = 0; i < numInputs; i++)
34 {
35 const TfLiteTensor* inputTensor = &tfLiteTensors[tfLiteNode->inputs->data[i]];
36 tfLiteInputs.push_back(inputTensor);
37 if (!IsValid(tfLiteContext, *inputTensor, sliceOperatorCode, nodeIndex))
38 {
39 return kTfLiteError;
40 }
41 }
42
Cathal Corbett839b9322022-11-18 08:52:18 +000043 // We save the begin and size tensors in our descriptor. Therefore we have to read those values from inputs
Jan Eilers2ffddda2021-02-03 09:14:30 +000044 int inputRank = tfLiteInputs[0]->dims->size;
Mike Kelly04f71202023-05-05 15:35:18 +010045 auto ReadInt32Input = [&](int inputIndex, std::vector<int32_t>& outputData, const char* name) -> TfLiteStatus
Jan Eilers2ffddda2021-02-03 09:14:30 +000046 {
47 if (tfLiteInputs[inputIndex]->type != kTfLiteInt32)
48 {
49 TF_LITE_MAYBE_KERNEL_LOG(
50 tfLiteContext,
Mike Kelly04f71202023-05-05 15:35:18 +010051 "TfLiteArmnnDelegate: The %s Tensor of the Slice operation needs to "
Jan Eilers2ffddda2021-02-03 09:14:30 +000052 "be of type int32. Operator: #%d node #%d: ",
Mike Kelly04f71202023-05-05 15:35:18 +010053 name, sliceOperatorCode, nodeIndex);
Jan Eilers2ffddda2021-02-03 09:14:30 +000054 return kTfLiteError;
55 }
56 int rank = tfLiteInputs[inputIndex]->dims->size;
57 if (rank != 1)
58 {
59 TF_LITE_MAYBE_KERNEL_LOG(
60 tfLiteContext,
Mike Kelly04f71202023-05-05 15:35:18 +010061 "TfLiteArmnnDelegate: The %s Tensor of the Slice operation needs to "
Jan Eilers2ffddda2021-02-03 09:14:30 +000062 "be a 1D-Tensor. Operator: #%d node #%d: ",
Mike Kelly04f71202023-05-05 15:35:18 +010063 name, sliceOperatorCode, nodeIndex);
Jan Eilers2ffddda2021-02-03 09:14:30 +000064 return kTfLiteError;
65 }
66 int numValues = tfLiteInputs[inputIndex]->dims->data[0];
67 if (numValues != inputRank)
68 {
69 TF_LITE_MAYBE_KERNEL_LOG(
70 tfLiteContext,
Mike Kelly04f71202023-05-05 15:35:18 +010071 "TfLiteArmnnDelegate: The number of values in the %s Tensor of the "
72 "Slice operation needs to be equal to the rank of the Input Tensor. Operator: #%d node #%d: ",
73 name, sliceOperatorCode, nodeIndex);
Jan Eilers2ffddda2021-02-03 09:14:30 +000074 return kTfLiteError;
75 }
76 // return tensor data
Mike Kelly04f71202023-05-05 15:35:18 +010077 auto* tensorDataPtr = tflite::GetTensorData<int32_t>(tfLiteInputs[inputIndex]);
78 outputData.assign(tensorDataPtr, tensorDataPtr + numValues);
Jan Eilers2ffddda2021-02-03 09:14:30 +000079 return kTfLiteOk;
80 };
81
Mike Kelly04f71202023-05-05 15:35:18 +010082 std::vector<int32_t> signedBegin;
83 if (ReadInt32Input(1, signedBegin, "Begin") != kTfLiteOk)
84 {
Jan Eilers2ffddda2021-02-03 09:14:30 +000085 return kTfLiteError;
Mike Kelly04f71202023-05-05 15:35:18 +010086 }
87
88 std::vector<int32_t> signedSize;
89 if (ReadInt32Input(2, signedSize, "Size") != kTfLiteOk)
90 {
Jan Eilers2ffddda2021-02-03 09:14:30 +000091 return kTfLiteError;
Mike Kelly04f71202023-05-05 15:35:18 +010092 }
93 std::vector<uint32_t> begin({ signedBegin.begin(), signedBegin.end() });
94 std::vector<uint32_t> size(signedSize.size());
95
96 for (unsigned int i = 0; i < signedSize.size(); ++i)
97 {
98 int signedValue = signedSize[i];
99 if (signedValue < -1 || signedValue > tfLiteInputs[0]->dims->data[i] - signedBegin[i])
100 {
101 TF_LITE_MAYBE_KERNEL_LOG(
102 tfLiteContext,
103 "TfLiteArmnnDelegate: Invalid value for Size. Size must be in range [-1, inputDimSize - begin] "
104 "[-1, %d] inclusive but was %d Operator: #%d node #%d: ",
105 tfLiteInputs[0]->dims->data[i] - signedBegin[i], signedValue, sliceOperatorCode,
106 nodeIndex);
107 return kTfLiteError;
108 }
109 if (signedValue == -1)
110 {
111 size[i] = tfLiteInputs[0]->dims->data[i] - signedBegin[i];
112 }
113 else
114 {
115 size[i] = static_cast<uint32_t>(signedValue);
116 }
117 }
Jan Eilers2ffddda2021-02-03 09:14:30 +0000118
119 // Write all data to the descriptor
Cathal Corbett839b9322022-11-18 08:52:18 +0000120 armnn::SliceDescriptor descriptor(begin, size);
Jan Eilers2ffddda2021-02-03 09:14:30 +0000121
122 // Validate output
123 const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]];
124 if (!IsValid(tfLiteContext, tfLiteOutputTensor, sliceOperatorCode, nodeIndex))
125 {
126 return kTfLiteError;
127 }
128
129 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(*tfLiteInputs[0]);
Sadik Armagan90a119b2022-08-05 16:12:49 +0100130 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true);
Jan Eilers2ffddda2021-02-03 09:14:30 +0000131
132 bool isSupported = false;
Cathal Corbett53837672022-09-01 11:34:37 +0100133 armnn::BackendId setBackend;
Jan Eilers2ffddda2021-02-03 09:14:30 +0000134 auto validateFunc = [&](const armnn::TensorInfo& outInfo, bool& isSupported)
135 {
Sadik Armaganbfa767c2022-02-09 14:58:03 +0000136 FORWARD_LAYER_SUPPORT_FUNC("SLICE",
Jan Eilers2ffddda2021-02-03 09:14:30 +0000137 tfLiteContext,
Cathal Corbett839b9322022-11-18 08:52:18 +0000138 IsSliceSupported,
Jan Eilers2ffddda2021-02-03 09:14:30 +0000139 delegateData.m_Backends,
140 isSupported,
Cathal Corbett53837672022-09-01 11:34:37 +0100141 setBackend,
Jan Eilers2ffddda2021-02-03 09:14:30 +0000142 inputTensorInfo,
143 outInfo,
144 descriptor);
145 };
146
147 if (!delegateData.m_Network)
148 {
149 validateFunc(outputTensorInfo, isSupported);
150 return isSupported ? kTfLiteOk : kTfLiteError;
151 }
152
Cathal Corbett53837672022-09-01 11:34:37 +0100153 // Add a Slice layer
Mike Kelly07169c82023-08-02 13:23:09 +0100154 auto layerName = GetLayerName(armnn::LayerType::Slice, nodeIndex);
Mike Kelly04f71202023-05-05 15:35:18 +0100155 armnn::IConnectableLayer* layer = delegateData.m_Network->AddSliceLayer(descriptor, layerName.c_str());
Cathal Corbett53837672022-09-01 11:34:37 +0100156 layer->SetBackendId(setBackend);
Jan Eilers2ffddda2021-02-03 09:14:30 +0000157 ARMNN_ASSERT(layer != nullptr);
158
159 armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(0);
160 outputSlot.SetTensorInfo(outputTensorInfo);
161
Ryan OShea4c231de2023-01-17 15:19:20 +0000162 // try to connect the Constant Inputs if there are any
Mike Kelly07169c82023-08-02 13:23:09 +0100163 if (ProcessInputs(layer, delegateData, tfLiteContext, tfLiteNode, nodeIndex) != kTfLiteOk)
Ryan OShea4c231de2023-01-17 15:19:20 +0000164 {
165 return kTfLiteError;
166 }
167
Jan Eilers2ffddda2021-02-03 09:14:30 +0000168 // Connect
169 return Connect(layer, tfLiteNode, delegateData);
Sadik Armagan62483be2020-10-23 17:14:43 +0100170}
171
172} // namespace armnnDelegate
Cathal Corbett53837672022-09-01 11:34:37 +0100173