ArmNN
 25.11
Loading...
Searching...
No Matches
StridedSlice.cpp
Go to the documentation of this file.
1//
2// Copyright © 2017, 2024 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "StridedSlice.hpp"
7
9
10#include <cstring>
11
12namespace armnn
13{
14
15namespace
16{
17
18void PadParams(StridedSliceDescriptor& p, unsigned int dimCount)
19{
20 ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(dimCount <= 4, "Expected input with at most 4 dimensions");
21
22 const unsigned int beginIndicesCount =
23 armnn::numeric_cast<unsigned int>(p.m_Begin.size());
24
25 const unsigned int padCount = dimCount - beginIndicesCount;
26
27 p.m_Begin.resize(dimCount);
28 p.m_End.resize(dimCount);
29 p.m_Stride.resize(dimCount);
30
31 for (unsigned int i = beginIndicesCount; i > 0; --i)
32 {
33 p.m_Stride[i + padCount - 1] = p.m_Stride[i - 1];
34 p.m_Begin[i + padCount - 1] = p.m_Begin[i - 1];
35 p.m_End[i + padCount - 1] = p.m_End[i - 1];
36 }
37
38 for (unsigned int i = 0; i < padCount; ++i)
39 {
40 p.m_Stride[i] = 1;
41 p.m_Begin[i] = 0;
42 p.m_End[i] = 0;
43 }
44
45 p.m_ShrinkAxisMask <<= padCount;
46 p.m_EllipsisMask <<= padCount;
47 p.m_NewAxisMask <<= padCount;
48 p.m_BeginMask <<= padCount;
49 p.m_EndMask <<= padCount;
50 p.m_BeginMask |= (1 << padCount) - 1;
51 p.m_EndMask |= (1 << padCount) - 1;
52}
53
54bool LoopCondition(int index, int stop, int stride)
55{
56 return stride > 0 ? index >= stop : index <= stop;
57}
58
59TensorShape ExtendShape(const TensorShape& inputShape,
60 unsigned int newNumDimensions)
61{
62 if (inputShape.GetNumDimensions() >= newNumDimensions)
63 {
64 return inputShape;
65 }
66
67 std::vector<unsigned int> newSizes(newNumDimensions, 0);
68
69 unsigned int diff = newNumDimensions - inputShape.GetNumDimensions();
70
71 for (unsigned int i = 0; i < diff; i++)
72 {
73 newSizes[i] = 1;
74 }
75
76 for (unsigned int i = diff; i < newNumDimensions; i++)
77 {
78 newSizes[i] = inputShape[i - diff];
79 }
80
81 return TensorShape(newNumDimensions, newSizes.data());
82}
83
84} // Anonymous namespace
85
86void StridedSlice(const TensorInfo& inputInfo,
87 const StridedSliceDescriptor& params,
88 const void* inputData,
89 void* outputData,
90 unsigned int dataTypeSize)
91{
92 if (inputData == nullptr)
93 {
94 throw armnn::InvalidArgumentException("Slice: Null inputData pointer");
95 }
96 if (outputData == nullptr)
97 {
98 throw armnn::InvalidArgumentException("Slice: Null outputData pointer");
99 }
100
101 const unsigned char* input = reinterpret_cast<const unsigned char*>(inputData);
102 unsigned char* output = reinterpret_cast<unsigned char*>(outputData);
103
104 const TensorShape inputShape = ExtendShape(inputInfo.GetShape(), 4);
105
106 StridedSliceDescriptor paddedParams = params;
107
108 // Pad parameters to 4 dimensions
109 PadParams(paddedParams, 4);
110
111 // Arrays containing the start and stop index for each axis (adjusted by set params/flags)
112 int startArray [4] = {0};
113 int stopArray [4] = {0};
114
115 // Getting paddedParams stop and start values for each axis
116 for(unsigned int i = 0; i < 4; ++i)
117 {
118 startArray[i] = paddedParams.GetStartForAxis(inputShape, i);
119 stopArray[i] = paddedParams.GetStopForAxis(inputShape, i, startArray[i]);
120 }
121
122 // Adjusting the EllipsisMask based on the NewAxisMask
123 // (if NewAxisMask extends an axis, the ellipsis flag is extended as well)
124 if(paddedParams.m_NewAxisMask > 0 && paddedParams.m_EllipsisMask > 0)
125 {
126 // Iterate until the current EllipsisMask 1-bit found
127 for(unsigned int i = 0; i < 4; ++i)
128 {
129 // If EllipsisMask bit found, adjust based on NewAxisMask and exit loop
130 if(paddedParams.m_EllipsisMask & (1 << i) && !(paddedParams.m_NewAxisMask & (1 << i)))
131 {
132 // If the previous bit is the NewAxisMask, set the EllipsisMask there
133 // (this condition was determined based on the unit tests expected data)
134 if(paddedParams.m_NewAxisMask & (1 << (i-1)))
135 {
136 paddedParams.m_EllipsisMask |= (1 << (i-1));
137 }
138 // Otherwise, extend the EllipsisMask by one bit
139 else
140 {
141 paddedParams.m_EllipsisMask |= (1 << (i+1));
142 }
143 break;
144 }
145 }
146 }
147
148 // Processing start and stop values based on the EllipsisMask and NewAxisMask
149 for(unsigned int i = 0, dimIdx = 0; i < 4; ++i)
150 {
151 // If the EllipsisMask is set, extend the start/stop to the input dimension size
152 if(paddedParams.m_EllipsisMask & (1 << dimIdx))
153 {
154 startArray[i] = 0;
155 stopArray[i] = armnn::numeric_cast<int>(inputShape[i]);
156 }
157 // Otherwise, if the NewAxisMask is set, shift all following start/stop values to the left
158 else if(paddedParams.m_NewAxisMask & (1 << dimIdx))
159 {
160 // Increment dimIdx - skip the current dimension for which NewAxisMask is set
161 ++dimIdx;
162 }
163
164 // If the index of the currently processed dimension is higher than
165 // the index of the current start/stop array position, shift start/stop values
166 if(dimIdx > i && !(paddedParams.m_EllipsisMask & (1 << dimIdx)))
167 {
168 if(dimIdx < 4)
169 {
170 startArray[i] = startArray[dimIdx];
171 stopArray[i] = stopArray[dimIdx];
172 }
173 else
174 {
175 // If dimIdx is greater than the amount of available dimensions,
176 // instead of shifting the next ones, create new start/stop values
177 if(paddedParams.m_EllipsisMask > 0)
178 {
179 // The new values are 0,1 if there is an EllipsisMask bit present
180 startArray[i] = 0;
181 stopArray[i] = 1;
182 }
183 else
184 {
185 // Otherwise, select the entire inputTensor dimension size
186 startArray[i] = 0;
187 stopArray[i] = armnn::numeric_cast<int>(inputShape[i]);
188 }
189 }
190 }
191 ++dimIdx;
192 }
193
194 const int step = armnn::numeric_cast<int>(dataTypeSize);
195
196 for (int in0 = startArray[0];
197 !LoopCondition(in0, stopArray[0], paddedParams.m_Stride[0]);
198 in0 += paddedParams.m_Stride[0])
199 {
200 for (int in1 = startArray[1];
201 !LoopCondition(in1, stopArray[1], paddedParams.m_Stride[1]);
202 in1 += paddedParams.m_Stride[1])
203 {
204 for (int in2 = startArray[2];
205 !LoopCondition(in2, stopArray[2], paddedParams.m_Stride[2]);
206 in2 += paddedParams.m_Stride[2])
207 {
208 for (int in3 = startArray[3];
209 !LoopCondition(in3, stopArray[3], paddedParams.m_Stride[3]);
210 in3 += paddedParams.m_Stride[3])
211 {
212 int dim1 = armnn::numeric_cast<int>(inputShape[1]);
213 int dim2 = armnn::numeric_cast<int>(inputShape[2]);
214 int dim3 = armnn::numeric_cast<int>(inputShape[3]);
215
216 int inputOffset = (((in0 * dim1 + in1) * dim2 + in2) * dim3 + in3) * step;
217 ::memcpy(output, input + inputOffset, dataTypeSize);
218 output += step;
219 }
220 }
221 }
222 }
223}
224
225} // namespace armnn
#define ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(_cond, _str)
const TensorShape & GetShape() const
Definition Tensor.hpp:193
Copyright (c) 2021 ARM Limited and Contributors.
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
A StridedSliceDescriptor for the StridedSliceLayer.
std::vector< int > m_Stride
Stride values for the input that will be sliced.
int32_t m_NewAxisMask
New axis mask value.
int GetStartForAxis(const TensorShape &inputShape, unsigned int axis) const
int32_t m_EllipsisMask
Ellipsis mask value.
int GetStopForAxis(const TensorShape &inputShape, unsigned int axis, int startForAxis) const