ArmNN
 24.08
Tensor.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 "armnn/Tensor.hpp"
7 #include "armnn/Utils.hpp"
8 #include "armnn/Exceptions.hpp"
9 #include "armnn/TypesUtils.hpp"
10 
11 #include <armnn/utility/Assert.hpp>
13 
14 #include <iostream>
15 
16 #include <sstream>
17 
18 namespace armnn
19 {
20 
21 // ---
22 // --- TensorShape
23 // ---
24 
26  : m_NumDimensions(0), m_Dimensionality(Dimensionality::Specified)
27 {
28 }
29 
30 TensorShape::TensorShape(unsigned int numDimensions, bool initDimensionsSpecificity)
31  : m_NumDimensions(numDimensions), m_Dimensionality(Dimensionality::Specified)
32 {
33  CheckValidNumDimensions(numDimensions);
34 
35  std::fill(m_Dimensions.begin(), m_Dimensions.begin() + m_NumDimensions, 0);
36  std::fill(m_DimensionsSpecificity.begin(), m_DimensionsSpecificity.begin() + m_NumDimensions,
37  initDimensionsSpecificity);
38 }
39 
40 TensorShape::TensorShape(const unsigned int numDimensions, const unsigned int* const dimensionSizes)
41  : m_NumDimensions(numDimensions), m_Dimensionality(Dimensionality::Specified)
42 {
43  CheckValidNumDimensions(numDimensions);
44 
45  if (dimensionSizes == nullptr)
46  {
47  throw InvalidArgumentException("Tensor dimensionSizes must not be NULL");
48  }
49 
50  std::copy(dimensionSizes, dimensionSizes + numDimensions, m_Dimensions.begin());
51  std::fill(m_DimensionsSpecificity.begin(), m_DimensionsSpecificity.begin() + m_NumDimensions, true);
52 }
53 
54 TensorShape::TensorShape(std::initializer_list<unsigned int> dimensionSizeList)
55  : TensorShape(armnn::numeric_cast<unsigned int>(dimensionSizeList.size()), dimensionSizeList.begin())
56 {
57 }
58 
59 TensorShape::TensorShape(unsigned int numDimensions,
60  const unsigned int* const dimensionSizes,
61  const bool* const dimensionsSpecificity)
62  : m_NumDimensions(numDimensions), m_Dimensionality(Dimensionality::Specified)
63 {
64  CheckValidNumDimensions(numDimensions);
65 
66  if (dimensionSizes == nullptr)
67  {
68  throw InvalidArgumentException("Tensor dimensionSizes must not be NULL");
69  }
70 
71  if (dimensionsSpecificity == nullptr)
72  {
73  throw InvalidArgumentException("Tensor dimensionsSpecificity must not be NULL");
74  }
75 
76  std::copy(dimensionSizes, dimensionSizes + numDimensions, m_Dimensions.begin());
77  std::copy(dimensionsSpecificity, dimensionsSpecificity + numDimensions, m_DimensionsSpecificity.begin());
78 }
79 
80 TensorShape::TensorShape(std::initializer_list<unsigned int> dimensionSizeList,
81  std::initializer_list<bool> dimensionsSpecificityList)
82 {
83  auto numDimensions = static_cast<unsigned int>(dimensionSizeList.size());
84  if (dimensionsSpecificityList.size() != numDimensions)
85  {
86  throw InvalidArgumentException("Tensors dimensionSizeList and dimensionsSpecificityList must be same size");
87  }
88 
89  *this = TensorShape(numDimensions, dimensionSizeList.begin(), dimensionsSpecificityList.begin());
90 }
91 
93 : m_Dimensionality(dimensionality)
94 {
95  switch (dimensionality)
96  {
98  throw InvalidArgumentException("Use other constructor to specify the rest of the values, this one is only "
99  "for tensors that have an unknown number of dimensions or that are scalar");
100  break;
102  m_NumDimensions = 0;
103  m_Dimensions = {0};
104  m_DimensionsSpecificity = {false};
105  break;
107  m_NumDimensions = 1;
108  m_Dimensions = {1};
109  m_DimensionsSpecificity = {true};
110  break;
111  default:
112  throw InvalidArgumentException("Invalid Dimensionality value");
113  }
114 }
115 
117  : m_NumDimensions(other.m_NumDimensions), m_Dimensionality(other.m_Dimensionality)
118 {
119  std::copy(other.m_Dimensions.cbegin(), other.m_Dimensions.cbegin() + other.m_NumDimensions, m_Dimensions.begin());
120  std::copy(other.m_DimensionsSpecificity.cbegin(), other.m_DimensionsSpecificity.cbegin() + other.m_NumDimensions,
121  m_DimensionsSpecificity.begin());
122 }
123 
125 {
126  m_NumDimensions = other.m_NumDimensions;
127  m_Dimensionality = other.m_Dimensionality;
128  std::copy(other.m_Dimensions.cbegin(), other.m_Dimensions.cbegin() + other.m_NumDimensions, m_Dimensions.begin());
129  std::copy(other.m_DimensionsSpecificity.cbegin(), other.m_DimensionsSpecificity.cbegin() + other.m_NumDimensions,
130  m_DimensionsSpecificity.begin());
131  return *this;
132 }
133 
134 // read
135 unsigned int TensorShape::operator[](unsigned int i) const
136 {
137  CheckUnspecifiedNumDimensions();
138  CheckDimensionIndex(i);
139  CheckDimensionSpecified(i);
140 
141  return m_Dimensions.at(i);
142 }
143 
144 // read and write
145 unsigned int& TensorShape::operator[](unsigned int i)
146 {
147  if (Dimensionality::Scalar == m_Dimensionality)
148  {
149  std::stringstream errorMessage;
150  errorMessage << "TensorShape with Dimensionality::Scalar must be const to use operator[]";
151  throw InvalidArgumentException(errorMessage.str(), CHECK_LOCATION());
152  }
153  CheckUnspecifiedNumDimensions();
154  CheckDimensionIndex(i);
155  CheckDimensionSpecified(i);
156 
157  return m_Dimensions.at(i);
158 }
159 
160 bool TensorShape::operator==(const TensorShape& other) const
161 {
162  return ((m_NumDimensions == other.m_NumDimensions) &&
163  (m_Dimensionality == other.m_Dimensionality) &&
164  std::equal(m_Dimensions.cbegin(), m_Dimensions.cbegin() + m_NumDimensions, other.m_Dimensions.cbegin()) &&
165  std::equal(m_DimensionsSpecificity.cbegin(), m_DimensionsSpecificity.cbegin() + m_NumDimensions,
166  other.m_DimensionsSpecificity.cbegin()));
167 }
168 
169 bool TensorShape::operator!=(const TensorShape& other) const
170 {
171  return !(*this == other);
172 }
173 
174 unsigned int TensorShape::GetNumDimensions() const
175 {
176  CheckUnspecifiedNumDimensions();
177 
178  return m_NumDimensions;
179 }
180 
181 unsigned int TensorShape::GetNumElements() const
182 {
183  CheckUnspecifiedNumDimensions();
184 
185  if (m_NumDimensions == 0)
186  {
187  return 0;
188  }
189 
190  unsigned int count = 1;
191  bool atLeastOneDimensionSpecified = false;
192  for (unsigned int i = 0; i < m_NumDimensions; ++i)
193  {
194  if (m_DimensionsSpecificity[i])
195  {
196  atLeastOneDimensionSpecified = true;
197  count *= m_Dimensions[i];
198  }
199  }
200 
201  if (atLeastOneDimensionSpecified)
202  {
203  return count;
204  }
205  else
206  {
207  return 0;
208  }
209 }
210 
211 bool TensorShape:: GetDimensionSpecificity(unsigned int i) const
212 {
213  CheckUnspecifiedNumDimensions();
214  CheckDimensionIndex(i);
215 
216  return m_DimensionsSpecificity[i];
217 }
218 
219 void TensorShape::SetNumDimensions(unsigned int numDimensions, bool initDimensionsSpecificity)
220 {
221  CheckScalar();
222  CheckSpecifiedNumDimensions();
223  CheckValidNumDimensions(numDimensions);
224 
225  m_NumDimensions = numDimensions;
226  m_Dimensionality = Dimensionality::Specified;
227  std::fill(m_Dimensions.begin(), m_Dimensions.begin() + m_NumDimensions, 0);
228  std::fill(m_DimensionsSpecificity.begin(), m_DimensionsSpecificity.begin() + m_NumDimensions,
229  initDimensionsSpecificity);
230 }
231 
232 void TensorShape::SetDimensionSize(unsigned int i, unsigned int dimensionSize)
233 {
234  CheckScalar();
235  CheckDimensionIndex(i);
236 
237  m_Dimensions[i] = dimensionSize;
238  m_DimensionsSpecificity[i] = true;
239 }
240 
242 {
243  CheckUnspecifiedNumDimensions();
244 
245  bool areAllDimensionsSpecified = true;
246  for (unsigned int i = 0; i < m_NumDimensions; ++i)
247  {
248  if (!m_DimensionsSpecificity[i])
249  {
250  areAllDimensionsSpecified = false;
251  break;
252  }
253  }
254  return areAllDimensionsSpecified;
255 }
256 
258 {
259  CheckUnspecifiedNumDimensions();
260 
261  bool isAtLeastOneDimensionSpecified = false;
262  for (unsigned int i = 0; i < m_NumDimensions; ++i)
263  {
264  if (m_DimensionsSpecificity[i])
265  {
266  isAtLeastOneDimensionSpecified = true;
267  break;
268  }
269  }
270  return isAtLeastOneDimensionSpecified;
271 }
272 
273 void TensorShape::CheckDimensionIndex(unsigned int i) const
274 {
275  if (i >= m_NumDimensions)
276  {
277  std::stringstream errorMessage;
278  errorMessage << "Invalid dimension index: " << i << " (number of dimensions is " << m_NumDimensions << ")";
279  throw InvalidArgumentException(errorMessage.str(), CHECK_LOCATION());
280  }
281 }
282 
283 void TensorShape::CheckValidNumDimensions(unsigned int numDimensions)
284 {
285  if (numDimensions < 1)
286  {
287  throw InvalidArgumentException("Tensor numDimensions must be greater than 0", CHECK_LOCATION());
288  }
289 
290  if (numDimensions > MaxNumOfTensorDimensions)
291  {
292  throw InvalidArgumentException("Tensor numDimensions must be less than or equal to MaxNumOfTensorDimensions"
293  , CHECK_LOCATION());
294  }
295 }
296 
297 void TensorShape::CheckDimensionSpecified(unsigned int i) const
298 {
299  if (!m_DimensionsSpecificity[i])
300  {
301  std::stringstream errorMessage;
302  errorMessage << "Dimension index: " << i << " not specified. Tensor shape not inferred yet.";
303  throw InvalidArgumentException(errorMessage.str(), CHECK_LOCATION());
304  }
305 }
306 
307 void TensorShape::CheckScalar() const
308 {
309  if (Dimensionality::Scalar == m_Dimensionality)
310  {
311  std::stringstream errorMessage;
312  errorMessage << "Invalid action on a tensor shape that holds a scalar value.";
313  throw InvalidArgumentException(errorMessage.str(), CHECK_LOCATION());
314  }
315 }
316 
317 void TensorShape::CheckUnspecifiedNumDimensions() const
318 {
319  if (Dimensionality::NotSpecified == m_Dimensionality)
320  {
321  std::stringstream errorMessage;
322  errorMessage << "Invalid action on a tensor shape that has unknown number of dimensions.";
323  throw InvalidArgumentException(errorMessage.str(), CHECK_LOCATION());
324  }
325 }
326 
327 void TensorShape::CheckSpecifiedNumDimensions() const
328 {
329  if (Dimensionality::Specified == m_Dimensionality)
330  {
331  std::stringstream errorMessage;
332  errorMessage << "Invalid action on a tensor shape that has known number of dimensions.";
333  throw InvalidArgumentException(errorMessage.str(), CHECK_LOCATION());
334  }
335 }
336 
337 // ---
338 // --- TensorInfo
339 // ---
340 
342 : m_DataType(DataType::Float32), m_IsConstant(false)
343 {
344 }
345 
347  DataType dataType,
348  float quantizationScale,
349  int32_t quantizationOffset,
350  bool isConstant)
351  : m_Shape(shape)
352  , m_DataType(dataType)
353  , m_IsConstant(isConstant)
354 {
355  SetQuantizationScale(quantizationScale);
356  SetQuantizationOffset(quantizationOffset);
357 }
358 
359 TensorInfo::TensorInfo(unsigned int numDimensions,
360  const unsigned int* dimensionSizes,
361  DataType dataType,
362  float quantizationScale,
363  int32_t quantizationOffset,
364  bool isConstant)
365  : m_Shape(numDimensions, dimensionSizes), m_DataType(dataType), m_IsConstant(isConstant)
366 {
367  SetQuantizationScale(quantizationScale);
368  SetQuantizationOffset(quantizationOffset);
369 }
370 
372  DataType dataType,
373  const std::vector<float>& quantizationScales,
374  unsigned int quantizationDim,
375  bool isConstant)
376  : m_Shape(shape)
377  , m_DataType(dataType)
378  , m_IsConstant(isConstant)
379 {
380  SetQuantizationScales(quantizationScales);
381  SetQuantizationDim(MakeOptional<unsigned int>(quantizationDim));
382 }
383 
384 TensorInfo::TensorInfo(unsigned int numDimensions,
385  const unsigned int* dimensionSizes,
386  DataType dataType,
387  const std::vector<float>& quantizationScales,
388  unsigned int quantizationDim,
389  bool isConstant)
390  : m_Shape(numDimensions, dimensionSizes)
391  , m_DataType(dataType)
392  , m_IsConstant(isConstant)
393 {
394  SetQuantizationScales(quantizationScales);
395  SetQuantizationDim(MakeOptional<unsigned int>(quantizationDim));
396 }
397 
399 : m_Shape(other.m_Shape)
400 , m_DataType(other.m_DataType)
401 , m_IsConstant(other.m_IsConstant)
402 , m_Quantization(other.m_Quantization)
403 {}
404 
406 {
407  m_Shape = other.m_Shape;
408  m_DataType = other.m_DataType;
409  m_Quantization = other.m_Quantization;
410  m_IsConstant = other.m_IsConstant;
411  return *this;
412 }
413 
414 bool TensorInfo::operator==(const TensorInfo& other) const
415 {
416  return ((m_Shape == other.m_Shape) &&
417  (m_DataType == other.m_DataType) &&
418  (m_Quantization == other.m_Quantization) &&
419  (m_IsConstant == other.m_IsConstant));
420 }
421 
422 bool TensorInfo::operator!=(const TensorInfo& other) const
423 {
424  return !(*this == other);
425 }
426 
427 unsigned int TensorInfo::GetNumBytes() const
428 {
429  return GetDataTypeSize(m_DataType) * GetNumElements();
430 }
431 
432 bool TensorInfo::IsTypeSpaceMatch(const TensorInfo& other) const
433 {
434  bool match = true;
435 
436  match &= m_DataType == other.m_DataType;
437 
439  {
440  match &= GetQuantizationScale() == other.GetQuantizationScale() &&
442  }
443  return match;
444 }
445 
447 {
448  return HasMultipleQuantizationScales() || m_Quantization.m_QuantizationDim.has_value();
449 }
450 
451 std::vector<float> TensorInfo::GetQuantizationScales() const
452 {
453  return m_Quantization.m_Scales;
454 }
455 
456 void TensorInfo::SetQuantizationScales(const std::vector<float>& scales)
457 {
458  m_Quantization.m_Scales = scales;
459 }
460 
462 {
463  if (m_Quantization.m_Scales.empty())
464  {
465  // NOTE: old default for backward compatibility
466  return 1.0f;
467  }
468 
470  {
471  throw RuntimeException("Invalid call to GetQuantizationScale on a tensor with multiple scale values. Use "
472  "GetQuantizationScales instead.");
473  }
474  return m_Quantization.m_Scales[0];
475 }
476 
478 {
479  m_Quantization.m_Scales = { scale };
480 }
481 
483 {
484  if (!m_Quantization.m_Offset.has_value())
485  {
486  // NOTE: old default for backward compatibility
487  return 0;
488  }
489 
490  return m_Quantization.m_Offset.value();
491 }
492 
494 {
495  m_Quantization.m_Offset = MakeOptional<int32_t>(offset);
496 }
497 
499 {
500  return m_Quantization.m_QuantizationDim;
501 }
502 
504 {
505  m_Quantization.m_QuantizationDim = quantizationDim;
506 }
507 
509 {
510  return IsQuantizedType(m_DataType);
511 }
512 
514 {
515  return m_IsConstant;
516 }
517 
518 void TensorInfo::SetConstant(const bool IsConstant)
519 {
520  m_IsConstant = IsConstant;
521 }
522 
523 // ---
524 // --- BaseTensor
525 // ---
526 
527 template<typename MemoryType>
529  : m_MemoryArea(nullptr)
530 {
531 }
532 
533 template<typename MemoryType>
534 BaseTensor<MemoryType>::BaseTensor(const TensorInfo& info, MemoryType memoryArea)
535  : m_MemoryArea(memoryArea)
536  , m_Info(info)
537 {
538 }
539 
540 template<typename MemoryType>
542  : m_MemoryArea(other.m_MemoryArea)
543  , m_Info(other.GetInfo())
544 {
545 }
546 
547 template<typename MemoryType>
549 {
550  m_Info = other.m_Info;
551  m_MemoryArea = other.m_MemoryArea;
552  return *this;
553 }
554 
555 // Explicit instantiations.
556 template class BaseTensor<const void*>;
557 template class BaseTensor<void*>;
558 
559 } // namespace armnn
armnn::TensorShape::SetNumDimensions
void SetNumDimensions(unsigned int numDimensions, bool initDimensionsSpecificity=false)
Sets the tensor rank and therefore the Dimensionality is set to Specified if it was not.
Definition: Tensor.cpp:219
armnn::TensorInfo::SetQuantizationDim
void SetQuantizationDim(const Optional< unsigned int > &quantizationDim)
Definition: Tensor.cpp:503
armnn::TensorInfo::GetNumElements
unsigned int GetNumElements() const
Definition: Tensor.hpp:198
armnn::TensorInfo::GetNumBytes
unsigned int GetNumBytes() const
Definition: Tensor.cpp:427
armnn::Optional< unsigned int >
armnn::TensorInfo::GetQuantizationScales
std::vector< float > GetQuantizationScales() const
Definition: Tensor.cpp:451
armnn::TensorShape::GetDimensionSpecificity
bool GetDimensionSpecificity(unsigned int i) const
Gets information about if the dimension size has been specified or not.
Definition: Tensor.cpp:211
armnn::TensorInfo::GetQuantizationScale
float GetQuantizationScale() const
Definition: Tensor.cpp:461
TypesUtils.hpp
armnn::TensorInfo
Definition: Tensor.hpp:152
CHECK_LOCATION
#define CHECK_LOCATION()
Definition: Exceptions.hpp:203
armnn::DataType::Float32
@ Float32
armnn::TensorShape::AreAllDimensionsSpecified
bool AreAllDimensionsSpecified() const
Checks if there is at least one dimension not specified.
Definition: Tensor.cpp:241
armnn::BaseTensor::m_MemoryArea
MemoryType m_MemoryArea
Definition: Tensor.hpp:314
armnn::MaxNumOfTensorDimensions
constexpr unsigned int MaxNumOfTensorDimensions
Definition: Types.hpp:31
armnn::TensorShape::operator[]
unsigned int operator[](unsigned int i) const
Read only operator.
Definition: Tensor.cpp:135
armnn::TensorInfo::HasPerAxisQuantization
bool HasPerAxisQuantization() const
Definition: Tensor.cpp:446
armnn::TensorInfo::IsConstant
bool IsConstant() const
Definition: Tensor.cpp:513
armnn::numeric_cast
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
Definition: NumericCast.hpp:35
NumericCast.hpp
armnn::TensorShape::operator=
TensorShape & operator=(const TensorShape &other)
Assignation function.
Definition: Tensor.cpp:124
Assert.hpp
armnn::TensorShape::SetDimensionSize
void SetDimensionSize(unsigned int i, unsigned int dimensionSize)
Sets the size of the indicated dimension and Specificity for that dimension is set to true.
Definition: Tensor.cpp:232
armnn::Dimensionality
Dimensionality
Definition: Types.hpp:172
armnn::TensorShape
Definition: Tensor.hpp:20
armnn::TensorInfo::SetQuantizationScale
void SetQuantizationScale(float scale)
Definition: Tensor.cpp:477
armnn::TensorInfo::SetQuantizationScales
void SetQuantizationScales(const std::vector< float > &scales)
Definition: Tensor.cpp:456
armnn::TensorShape::IsAtLeastOneDimensionSpecified
bool IsAtLeastOneDimensionSpecified() const
Checks if there is at least one dimension specified.
Definition: Tensor.cpp:257
armnn::TensorShape::GetNumDimensions
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
Definition: Tensor.cpp:174
armnn::BaseTensor::BaseTensor
BaseTensor()
Empty (invalid) constructor.
Definition: Tensor.cpp:528
Utils.hpp
armnn::TensorInfo::GetQuantizationDim
Optional< unsigned int > GetQuantizationDim() const
Definition: Tensor.cpp:498
armnn::TensorInfo::HasMultipleQuantizationScales
bool HasMultipleQuantizationScales() const
Definition: Tensor.hpp:203
armnn::DataType
DataType
Definition: Types.hpp:48
armnn::TensorInfo::IsQuantized
bool IsQuantized() const
Definition: Tensor.cpp:508
armnn::Dimensionality::Scalar
@ Scalar
armnn::TensorInfo::IsTypeSpaceMatch
bool IsTypeSpaceMatch(const TensorInfo &other) const
Check that the types are the same and, if quantize, that the quantization parameters are the same.
Definition: Tensor.cpp:432
armnn::TensorInfo::operator==
bool operator==(const TensorInfo &other) const
Definition: Tensor.cpp:414
armnn::InvalidArgumentException
Definition: Exceptions.hpp:80
armnn::TensorInfo::TensorInfo
TensorInfo()
Empty (invalid) constructor.
Definition: Tensor.cpp:341
armnn::GetDataTypeSize
constexpr unsigned int GetDataTypeSize(DataType dataType)
Definition: TypesUtils.hpp:182
armnn::TensorShape::operator!=
bool operator!=(const TensorShape &other) const
Inequality comparison operator.
Definition: Tensor.cpp:169
armnn::Dimensionality::NotSpecified
@ NotSpecified
armnn::RuntimeException
Definition: Exceptions.hpp:120
armnn::BaseTensor
Definition: Tensor.hpp:279
armnn::BoostLogSeverityMapping::info
@ info
armnn::TensorInfo::operator!=
bool operator!=(const TensorInfo &other) const
Definition: Tensor.cpp:422
armnn::TensorInfo::operator=
TensorInfo & operator=(const TensorInfo &other)
Definition: Tensor.cpp:405
armnn::TensorInfo::SetQuantizationOffset
void SetQuantizationOffset(int32_t offset)
Definition: Tensor.cpp:493
armnn::Dimensionality::Specified
@ Specified
Tensor.hpp
armnn::IsQuantizedType
constexpr bool IsQuantizedType()
Definition: TypesUtils.hpp:311
Exceptions.hpp
armnn
Copyright (c) 2021 ARM Limited and Contributors.
Definition: 01_00_quick_start.dox:6
armnn::TensorShape::operator==
bool operator==(const TensorShape &other) const
Equality comparison operator.
Definition: Tensor.cpp:160
armnn::TensorInfo::SetConstant
void SetConstant(const bool IsConstant=true)
Marks the data corresponding to this tensor info as constant.
Definition: Tensor.cpp:518
armnn::TensorInfo::GetQuantizationOffset
int32_t GetQuantizationOffset() const
Definition: Tensor.cpp:482
armnn::TensorShape::GetNumElements
unsigned int GetNumElements() const
Function that calculates the tensor elements by multiplying all dimension size which are Specified.
Definition: Tensor.cpp:181
armnn::TensorShape::TensorShape
TensorShape()
Empty (invalid) constructor.
Definition: Tensor.cpp:25