ArmNN
 24.08
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 
12 namespace armnn
13 {
14 
15 namespace
16 {
17 
18 void 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 
54 bool LoopCondition(int index, int stop, int stride)
55 {
56  return stride > 0 ? index >= stop : index <= stop;
57 }
58 
59 TensorShape 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 
86 void 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
armnn::StridedSliceDescriptor::m_EllipsisMask
int32_t m_EllipsisMask
Ellipsis mask value.
Definition: Descriptors.hpp:1357
armnn::TensorInfo
Definition: Tensor.hpp:152
NumericCast.hpp
armnn::StridedSliceDescriptor::GetStopForAxis
int GetStopForAxis(const TensorShape &inputShape, unsigned int axis, int startForAxis) const
Definition: Descriptors.cpp:420
armnn::TensorShape
Definition: Tensor.hpp:20
armnn::InvalidArgumentException
Definition: Exceptions.hpp:80
armnn::StridedSliceDescriptor::m_Stride
std::vector< int > m_Stride
Stride values for the input that will be sliced.
Definition: Descriptors.hpp:1346
armnn::StridedSliceDescriptor
A StridedSliceDescriptor for the StridedSliceLayer.
Definition: Descriptors.hpp:1303
armnn::TensorInfo::GetShape
const TensorShape & GetShape() const
Definition: Tensor.hpp:193
armnn::StridedSliceDescriptor::GetStartForAxis
int GetStartForAxis(const TensorShape &inputShape, unsigned int axis) const
Definition: Descriptors.cpp:393
armnn
Copyright (c) 2021 ARM Limited and Contributors.
Definition: 01_00_quick_start.dox:6
armnn::StridedSlice
void StridedSlice(const TensorInfo &inputInfo, const StridedSliceDescriptor &params, const void *inputData, void *outputData, unsigned int dataTypeSize)
Definition: StridedSlice.cpp:86
armnn::StridedSliceDescriptor::m_NewAxisMask
int32_t m_NewAxisMask
New axis mask value.
Definition: Descriptors.hpp:1360
StridedSlice.hpp
ARMNN_THROW_INVALIDARG_MSG_IF_FALSE
#define ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(_cond, _str)
Definition: Exceptions.hpp:210