ArmNN
 25.11
Loading...
Searching...
No Matches
Descriptors.cpp
Go to the documentation of this file.
1//
2// Copyright © 2017-2024 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
6#include "armnn/Logging.hpp"
7
10
11#include <algorithm>
12#include <array>
13#include <vector>
14
15#include <fmt/format.h>
16
17namespace armnn
18{
19
20PermutationVector::PermutationVector(const ValueType *dimMappings, const SizeType numDimMappings)
21{
22 // Validation
23
24 if (numDimMappings > MaxNumOfTensorDimensions)
25 {
27 fmt::format("The number of mappings ({0}) cannot be greater "
28 "than the maximum number of dimensions supported ({1})",
29 numDimMappings,
31 }
32
33 if ((dimMappings == nullptr) && (numDimMappings != 0))
34 {
35 throw InvalidArgumentException("Dimension mappings must not be NULL if the number of mappings is positive");
36 }
37
38 for (SizeType i = 0; i < numDimMappings; ++i)
39 {
40 const ValueType dstIndex = dimMappings[i];
41 if (dstIndex >= numDimMappings)
42 {
44 fmt::format("Dimension mapping at index {0} is invalid: "
45 "{1} is outside of the valid range [0,{2}]",
46 i,
47 dstIndex,
48 (numDimMappings - 1)));
49 }
50 }
51
52 // Validation: Detect duplicates
53 {
54 std::array<bool, MaxNumOfTensorDimensions> observedDims;
55 observedDims.fill(false);
56
57 for (SizeType i = 0; i < numDimMappings; ++i)
58 {
59 const ValueType dstIndex = dimMappings[i];
60 if (observedDims[dstIndex])
61 {
62 throw InvalidArgumentException("Invalid dimension mappings: Two or more source dimensions are mapped "
63 "to the same output dimension");
64 }
65 observedDims[dstIndex] = true;
66 }
67 }
68
69 // Initialize
70 for (SizeType i = 0; i < numDimMappings; ++i)
71 {
72 m_DimMappings[i] = dimMappings[i];
73 }
74 m_NumDimMappings = numDimMappings;
75}
76
77PermutationVector::PermutationVector(std::initializer_list<ValueType> dimMappings)
78 : PermutationVector(dimMappings.begin(), armnn::numeric_cast<SizeType>(dimMappings.size()))
79{
80}
81
83: m_ConcatAxis(1)
84, m_NumViews(0)
85, m_NumDimensions(0)
86, m_ViewOrigins(nullptr)
87{}
88
89OriginsDescriptor::OriginsDescriptor(uint32_t numViews, uint32_t numDimensions /*= 4*/)
90: m_ConcatAxis(1)
91, m_NumViews(numViews)
92, m_NumDimensions(numDimensions)
93, m_ViewOrigins(numViews && numDimensions > 0 ? new uint32_t *[numViews]() : nullptr)
94{
95 for (uint32_t i = 0; m_NumDimensions > 0 && i < m_NumViews; ++i)
96 {
97 m_ViewOrigins[i] = new uint32_t[m_NumDimensions]();
98 }
99}
100
102: m_ConcatAxis(other.m_ConcatAxis)
103, m_NumViews(other.m_NumViews)
104, m_NumDimensions(other.m_NumDimensions)
105, m_ViewOrigins(other.m_NumViews && other.m_NumDimensions > 0 ? new uint32_t *[other.m_NumViews]() : nullptr)
106{
107 for (uint32_t i = 0; m_NumDimensions > 0 && i < m_NumViews; ++i)
108 {
109 m_ViewOrigins[i] = new uint32_t[m_NumDimensions]();
110 memcpy(m_ViewOrigins[i], other.m_ViewOrigins[i], m_NumDimensions * sizeof(uint32_t));
111 }
112}
113
119
121{
122 for (uint32_t i = 0; m_NumDimensions > 0 && i < m_NumViews; ++i)
123 {
124 delete[] m_ViewOrigins[i];
125 }
126 delete[] m_ViewOrigins;
127}
128
130{
131 swap(*this, rhs);
132 return *this;
133}
134
136{
137 if (GetNumViews() != rhs.GetNumViews() ||
139 GetConcatAxis() != rhs.GetConcatAxis())
140 {
141 return false;
142 }
143
144 for (unsigned int i = 0u; i < GetNumViews(); ++i)
145 {
146 for (unsigned int j = 0u; j < GetNumDimensions(); ++j)
147 {
148 if (GetViewOrigin(i)[j] != rhs.GetViewOrigin(i)[j])
149 {
150 return false;
151 }
152 }
153 }
154
155 return true;
156}
157
158void OriginsDescriptor::SetConcatAxis(unsigned int concatAxis)
159{
160 m_ConcatAxis = concatAxis;
161}
163{
164 return m_ConcatAxis;
165}
166
167Status OriginsDescriptor::SetViewOriginCoord(uint32_t view, uint32_t coord, uint32_t value)
168{
169 if (view >= m_NumViews)
170 {
171 ARMNN_LOG(error) << "OriginsDescriptor::SetViewOriginCoord: view argument:" << view <<
172 " is out of range";
173 return Status::Failure;
174 }
175 if (coord >= m_NumDimensions)
176 {
177 ARMNN_LOG(error) << "OriginsDescriptor::SetViewOriginCoord: coord argument:" << coord <<
178 " is out of range";
179 return Status::Failure;
180 }
181
182 m_ViewOrigins[view][coord] = value;
183 return Status::Success;
184}
185
186
188{
189 return m_NumViews;
190}
191
193{
194 return m_NumDimensions;
195}
196
197const uint32_t* OriginsDescriptor::GetViewOrigin(uint32_t idx) const
198{
199 return m_ViewOrigins ? m_ViewOrigins[idx] : nullptr;
200}
201
202
203// Reorders the viewOrigins in accordance with the indices presented in newOrdering array.
204void OriginsDescriptor::ReorderOrigins(unsigned int* newOrdering, unsigned int numNewOrdering)
205{
206 ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(m_NumViews == numNewOrdering,
207 "number of views must match number of elements in the new ordering array");
208
209 std::vector<uint32_t*> viewOrigins(&m_ViewOrigins[0], &m_ViewOrigins[m_NumViews]);
210
211 for (unsigned int i = 0; i < numNewOrdering; ++i)
212 {
213 m_ViewOrigins[i] = viewOrigins[newOrdering[i]];
214 }
215}
216
218: m_Origins()
219, m_ViewSizes(nullptr)
220, m_IsAxisSet(false)
221, m_Axis(0)
222{}
223
224ViewsDescriptor::ViewsDescriptor(uint32_t numViews, uint32_t numDimensions /*= 4*/)
225 : m_Origins(numViews, numDimensions)
226 , m_ViewSizes(numViews > 0 && numDimensions > 0 ?
227 new uint32_t *[numViews]() : nullptr)
228 , m_IsAxisSet(false)
229 , m_Axis(0)
230{
231 if (m_ViewSizes)
232 {
233 for (uint32_t i = 0; GetNumDimensions() > 0 && i < GetNumViews(); ++i)
234 {
235 m_ViewSizes[i] = new uint32_t[GetNumDimensions()]();
236 }
237 }
238}
239
241 : m_Origins(other.m_Origins)
242 , m_ViewSizes(other.GetNumViews() > 0 && other.GetNumDimensions() > 0 ?
243 new uint32_t *[other.GetNumViews()]() : nullptr)
244 , m_IsAxisSet(other.m_IsAxisSet)
245 , m_Axis(other.m_Axis)
246{
247 if (m_ViewSizes)
248 {
249 for (uint32_t i = 0; GetNumDimensions() > 0 && i < GetNumViews(); ++i)
250 {
251 m_ViewSizes[i] = new uint32_t[GetNumDimensions()]();
252 memcpy(m_ViewSizes[i], other.m_ViewSizes[i], GetNumDimensions() * sizeof(uint32_t));
253 }
254 }
255}
256
259{
260 swap(*this, other);
261}
262
264{
265 if (m_ViewSizes)
266 {
267 for (uint32_t i = 0; GetNumDimensions() > 0 && i < GetNumViews(); ++i)
268 {
269 delete[] m_ViewSizes[i];
270 }
271 delete[] m_ViewSizes;
272 }
273}
274
276{
277 swap(*this, rhs);
278 return *this;
279}
280
282{
283 if (GetNumViews() != rhs.GetNumViews() || GetNumDimensions() != rhs.GetNumDimensions())
284 {
285 return false;
286 }
287
288 for (unsigned int i = 0u; i < GetNumViews(); ++i)
289 {
290 for (unsigned int j = 0u; j < GetNumDimensions(); ++j)
291 {
292 if (GetViewOrigin(i)[j] != rhs.GetViewOrigin(i)[j] || GetViewSizes(i)[j] != rhs.GetViewSizes(i)[j])
293 {
294 return false;
295 }
296 }
297 }
298
299 return true;
300}
301
303{
304 return m_Origins.GetNumViews();
305}
306
308{
309 return m_Origins.GetNumDimensions();
310}
311
312const uint32_t* ViewsDescriptor::GetViewOrigin(uint32_t idx) const
313{
314 return m_Origins.GetViewOrigin(idx);
315}
316
317Status ViewsDescriptor::SetViewOriginCoord(uint32_t view, uint32_t coord, uint32_t value)
318{
319 return m_Origins.SetViewOriginCoord(view, coord, value);
320}
321
322Status ViewsDescriptor::SetViewSize(uint32_t view, uint32_t coord, uint32_t value)
323{
324 if (!m_ViewSizes)
325 {
326 ARMNN_LOG(error) << "ViewsDescriptor::SetViewSize: invalid view sizes";
327 return Status::Failure;
328 }
329
330 if (view >= GetNumViews())
331 {
332 ARMNN_LOG(error) << "ViewsDescriptor::SetViewSize: view argument:" << view <<
333 " is out of range";
334 return Status::Failure;
335 }
336 if (coord >= GetNumDimensions())
337 {
338 ARMNN_LOG(error) << "ViewsDescriptor::SetViewSize: coord argument:" << coord <<
339 " is out of range";
340 return Status::Failure;
341 }
342
343 m_ViewSizes[view][coord] = value;
344 return Status::Success;
345}
346
347const uint32_t* ViewsDescriptor::GetViewSizes(uint32_t idx) const
348{
349 return m_ViewSizes ? m_ViewSizes[idx] : nullptr;
350}
351
353{
354 return m_Origins;
355}
356
358{
359 using std::swap;
360 swap(first.m_NumViews, second.m_NumViews);
361 swap(first.m_NumDimensions, second.m_NumDimensions);
362 swap(first.m_ViewOrigins, second.m_ViewOrigins);
363 swap(first.m_ConcatAxis, second.m_ConcatAxis);
364}
365
367{
368 using std::swap;
369 swap(first.m_Origins, second.m_Origins);
370 swap(first.m_ViewSizes, second.m_ViewSizes);
371 swap(first.m_IsAxisSet, second.m_IsAxisSet);
372 swap(first.m_Axis, second.m_Axis);
373}
374
375void ViewsDescriptor::SetAxis(int32_t axis)
376{
377 m_Axis = axis;
378 m_IsAxisSet = true;
379}
380
381/// Get the axis value.
383{
384 return m_Axis;
385}
386
387/// Returns true if an axis has been set.
389{
390 return m_IsAxisSet;
391}
392
394 unsigned int axis) const
395{
396 int start = m_Begin[axis];
397
398 if (m_BeginMask & (1 << axis))
399 {
400 if (m_Stride[axis] > 0)
401 {
402 start = std::numeric_limits<int>::min();
403 }
404 else
405 {
406 start = std::numeric_limits<int>::max();
407 }
408 }
409
410 const int axisSize = armnn::numeric_cast<int>(inputShape[axis]);
411 if (start < 0)
412 {
413 start += (axisSize);
414 }
415
416 return std::max(0, std::min(start, axisSize - 1));
417
418}
419
421 unsigned int axis,
422 int startForAxis) const
423{
424
425 if (m_ShrinkAxisMask & (1 << axis))
426 {
427 return startForAxis + 1;
428 }
429
430 int stop = m_End[axis];
431
432 if (m_EndMask & (1 << axis))
433 {
434 if (m_Stride[axis] > 0)
435 {
436 stop = std::numeric_limits<int>::max();
437 }
438 else
439 {
440 stop = std::numeric_limits<int>::min();
441 }
442 }
443
444 const int axisSize = armnn::numeric_cast<int>(inputShape[axis]);
445 if (stop < 0)
446 {
447 stop += axisSize;
448 }
449
450 return m_Stride[axis] > 0 ? std::max(0, std::min(stop, axisSize)) :
451 std::max(-1, std::min(stop, axisSize - 1));
452
453}
454
455uint32_t GetNumInputs(bool biasEnabled)
456{
457 unsigned int numInputs = 2;
458 if (biasEnabled)
459 {
460 numInputs = 3;
461 }
462 return numInputs;
463}
464
469
474
479
484
485std::pair<unsigned int, unsigned int> BatchMatMulDescriptor::GetAxesToMul(
486 DataLayout dataLayout,
487 const TensorShape& tensorShape)
488{
489 auto numDims = tensorShape.GetNumDimensions();
490 std::pair<unsigned int, unsigned int> axes = { numDims-2, numDims-1 };
491 switch(dataLayout)
492 {
494 case DataLayout::NHWC:
495 axes.first -= 1;
496 axes.second -= 1;
497 break;
499 case DataLayout::NCHW:
500 default:
501 break;
502 }
503 return axes;
504}
505
506std::vector<unsigned int> BatchMatMulDescriptor::GetAxesNotMul(
507 DataLayout dataLayout,
508 const TensorShape& tensorShape)
509{
510 auto axesToMul = BatchMatMulDescriptor::GetAxesToMul(dataLayout, tensorShape);
511 std::vector<unsigned int> axesNotMul;
512 for(unsigned int i = 0; i < tensorShape.GetNumDimensions(); i++)
513 {
514 if(i == axesToMul.first || i == axesToMul.second)
515 {
516 continue;
517 }
518 axesNotMul.push_back(i);
519 }
520 return axesNotMul;
521}
522
524 DataLayout dataLayout,
525 const TensorShape& tensorShape)
526{
527 std::vector<unsigned int> vec;
528 auto axesToMul = BatchMatMulDescriptor::GetAxesToMul(dataLayout, tensorShape);
529 for(unsigned int i = 0; i < tensorShape.GetNumDimensions(); i++)
530 {
531 if(i == axesToMul.first)
532 {
533 vec.push_back(i+1);
534 }
535 else if(i == axesToMul.second)
536 {
537 vec.push_back(i-1);
538 }
539 else
540 {
541 vec.push_back(i);
542 }
543 }
544 return PermutationVector(vec.data(),
545 static_cast<unsigned int>(vec.size()));
546}
547
548}
#define ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(_cond, _str)
#define ARMNN_LOG(severity)
Definition Logging.hpp:212
unsigned int SizeType
Definition Types.hpp:320
PermutationVector(const ValueType *dimMappings, SizeType numDimMappings)
unsigned int ValueType
Definition Types.hpp:319
ConstIterator begin() const
Definition Types.hpp:361
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
Definition Tensor.cpp:174
Copyright (c) 2021 ARM Limited and Contributors.
void swap(OriginsDescriptor &first, OriginsDescriptor &second)
uint32_t GetNumInputs(bool biasEnabled)
Status
enumeration
Definition Types.hpp:43
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
constexpr unsigned int MaxNumOfTensorDimensions
Definition Types.hpp:31
DataLayout
Definition Types.hpp:63
static std::pair< unsigned int, unsigned int > GetAxesToMul(DataLayout dataLayout, const TensorShape &tensorShape)
Static helper to get the two axes (for each input) for multiplication.
static PermutationVector GetPermuteVec(DataLayout dataLayout, const TensorShape &tensorShape)
Static helper to get the axes which will be transposed.
static std::vector< unsigned int > GetAxesNotMul(DataLayout dataLayout, const TensorShape &tensorShape)
Static helper to get the axes (for each input) that will not be multiplied together.
bool m_BiasEnabled
Enable/disable bias.
uint32_t GetNumInputs() const
Get the number of views/inputs.
bool m_BiasEnabled
Enable/disable bias.
uint32_t GetNumInputs() const
Get the number of views/inputs.
bool m_BiasEnabled
Enable/disable bias.
uint32_t GetNumInputs() const
Get the number of inputs.
bool m_BiasEnabled
Enable/disable bias.
An OriginsDescriptor for the ConcatLayer.
friend void swap(OriginsDescriptor &first, OriginsDescriptor &second)
Swap the ViewsDescriptor values first and second.
bool operator==(const OriginsDescriptor &rhs) const
Status SetViewOriginCoord(uint32_t view, uint32_t coord, uint32_t value)
@Brief Set the view origin coordinates.
uint32_t GetNumViews() const
Get the number of views.
unsigned int GetConcatAxis() const
Get the concatenation axis value.
void SetConcatAxis(unsigned int concatAxis)
Set the concatenation axis value.
uint32_t GetNumDimensions() const
Get the number of dimensions.
void ReorderOrigins(unsigned int *newOrdering, unsigned int numNewOrdering)
Reorders the viewOrigins in accordance with the indices presented in newOrdering array.
const uint32_t * GetViewOrigin(uint32_t idx) const
Return the view origin at the int value idx.
OriginsDescriptor & operator=(OriginsDescriptor rhs)
std::vector< int > m_Stride
Stride values for the input that will be sliced.
std::vector< int > m_Begin
Begin values for the input that will be sliced.
int32_t m_BeginMask
Begin mask value.
int32_t m_ShrinkAxisMask
Shrink axis mask value. If set, the nth specification shrinks the dimensionality by 1.
std::vector< int > m_End
End values for the input that will be sliced.
int32_t m_EndMask
End mask value.
int GetStartForAxis(const TensorShape &inputShape, unsigned int axis) const
int GetStopForAxis(const TensorShape &inputShape, unsigned int axis, int startForAxis) const
bool HasAxis() const
Returns true if an axis has been set.
int32_t GetAxis() const
Get the axis value.
Status SetViewOriginCoord(uint32_t view, uint32_t coord, uint32_t value)
@Brief Set the view origin coordinates.
uint32_t GetNumViews() const
Get the number of views.
const uint32_t * GetViewSizes(uint32_t idx) const
Get the view sizes at the int value idx.
friend void swap(ViewsDescriptor &first, ViewsDescriptor &second)
Swap the ViewsDescriptor value first and second.
uint32_t GetNumDimensions() const
Get the number of dimensions.
bool operator==(const ViewsDescriptor &rhs) const
const OriginsDescriptor & GetOrigins() const
Get the View Origins.
Status SetViewSize(uint32_t view, uint32_t coord, uint32_t value)
Set the size of the views.
ViewsDescriptor(uint32_t numViews, uint32_t numDimensions=4)
const uint32_t * GetViewOrigin(uint32_t idx) const
Get the view origin at the int value idx.
void SetAxis(int32_t axis)
Set the axis value.
ViewsDescriptor & operator=(ViewsDescriptor rhs)