ArmNN
 21.11
Tensor.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 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)
366  , m_DataType(dataType)
367  , m_IsConstant(isConstant)
368 {
369  SetQuantizationScale(quantizationScale);
370  SetQuantizationOffset(quantizationOffset);
371 }
372 
374  DataType dataType,
375  const std::vector<float>& quantizationScales,
376  unsigned int quantizationDim,
377  bool isConstant)
378  : m_Shape(shape)
379  , m_DataType(dataType)
380  , m_IsConstant(isConstant)
381 {
382  SetQuantizationScales(quantizationScales);
383  SetQuantizationDim(MakeOptional<unsigned int>(quantizationDim));
384 }
385 
386 TensorInfo::TensorInfo(unsigned int numDimensions,
387  const unsigned int* dimensionSizes,
388  DataType dataType,
389  const std::vector<float>& quantizationScales,
390  unsigned int quantizationDim,
391  bool isConstant)
392  : m_Shape(numDimensions, dimensionSizes)
393  , m_DataType(dataType)
394  , m_IsConstant(isConstant)
395 {
396  SetQuantizationScales(quantizationScales);
397  SetQuantizationDim(MakeOptional<unsigned int>(quantizationDim));
398 }
399 
401 : m_Shape(other.m_Shape)
402 , m_DataType(other.m_DataType)
403 , m_IsConstant(other.m_IsConstant)
404 , m_Quantization(other.m_Quantization)
405 {}
406 
408 {
409  m_Shape = other.m_Shape;
410  m_DataType = other.m_DataType;
411  m_Quantization = other.m_Quantization;
412  m_IsConstant = other.m_IsConstant;
413  return *this;
414 }
415 
416 bool TensorInfo::operator==(const TensorInfo& other) const
417 {
418  return ((m_Shape == other.m_Shape) &&
419  (m_DataType == other.m_DataType) &&
420  (m_Quantization == other.m_Quantization) &&
421  (m_IsConstant == other.m_IsConstant));
422 }
423 
424 bool TensorInfo::operator!=(const TensorInfo& other) const
425 {
426  return !(*this == other);
427 }
428 
429 unsigned int TensorInfo::GetNumBytes() const
430 {
431  return GetDataTypeSize(m_DataType) * GetNumElements();
432 }
433 
434 bool TensorInfo::IsTypeSpaceMatch(const TensorInfo& other) const
435 {
436  bool match = true;
437 
438  match &= m_DataType == other.m_DataType;
439 
441  {
442  match &= GetQuantizationScale() == other.GetQuantizationScale() &&
444  }
445  return match;
446 }
447 
449 {
450  return HasMultipleQuantizationScales() || m_Quantization.m_QuantizationDim.has_value();
451 }
452 
453 std::vector<float> TensorInfo::GetQuantizationScales() const
454 {
455  return m_Quantization.m_Scales;
456 }
457 
458 void TensorInfo::SetQuantizationScales(const std::vector<float>& scales)
459 {
460  m_Quantization.m_Scales = scales;
461 }
462 
464 {
465  if (m_Quantization.m_Scales.empty())
466  {
467  // NOTE: old default for backward compatibility
468  return 1.0f;
469  }
470 
472  return m_Quantization.m_Scales[0];
473 }
474 
476 {
477  m_Quantization.m_Scales = { scale };
478 }
479 
481 {
482  if (!m_Quantization.m_Offset.has_value())
483  {
484  // NOTE: old default for backward compatibility
485  return 0;
486  }
487 
488  return m_Quantization.m_Offset.value();
489 }
490 
492 {
493  m_Quantization.m_Offset = MakeOptional<int32_t>(offset);
494 }
495 
497 {
498  return m_Quantization.m_QuantizationDim;
499 }
500 
502 {
503  m_Quantization.m_QuantizationDim = quantizationDim;
504 }
505 
507 {
508  return IsQuantizedType(m_DataType);
509 }
510 
512 {
513  return m_IsConstant;
514 }
515 
517 {
518  m_IsConstant = IsConstant;
519 }
520 
521 // ---
522 // --- BaseTensor
523 // ---
524 
525 template<typename MemoryType>
527  : m_MemoryArea(nullptr)
528 {
529 }
530 
531 template<typename MemoryType>
532 BaseTensor<MemoryType>::BaseTensor(const TensorInfo& info, MemoryType memoryArea)
533  : m_MemoryArea(memoryArea)
534  , m_Info(info)
535 {
536 }
537 
538 template<typename MemoryType>
540  : m_MemoryArea(other.m_MemoryArea)
541  , m_Info(other.GetInfo())
542 {
543 }
544 
545 template<typename MemoryType>
547 {
548  m_Info = other.m_Info;
549  m_MemoryArea = other.m_MemoryArea;
550  return *this;
551 }
552 
553 // Explicit instantiations.
554 template class BaseTensor<const void*>;
555 template class BaseTensor<void*>;
556 
557 } // namespace armnn
unsigned int GetNumElements() const
Function that calculates the tensor elements by multiplying all dimension size which are Specified...
Definition: Tensor.cpp:181
bool IsConstant() const
Definition: Tensor.cpp:511
bool operator!=(const TensorShape &other) const
Inequality comparison operator.
Definition: Tensor.cpp:169
unsigned int operator[](unsigned int i) const
Read only operator.
Definition: Tensor.cpp:135
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:434
Dimensionality
Definition: Types.hpp:145
TensorShape & operator=(const TensorShape &other)
Assignation function.
Definition: Tensor.cpp:124
bool AreAllDimensionsSpecified() const
Checks if there is at least one dimension not specified.
Definition: Tensor.cpp:241
constexpr bool IsQuantizedType()
Definition: TypesUtils.hpp:280
bool HasPerAxisQuantization() const
Definition: Tensor.cpp:448
Optional< unsigned int > GetQuantizationDim() const
Definition: Tensor.cpp:496
unsigned int GetNumBytes() const
Definition: Tensor.cpp:429
Copyright (c) 2021 ARM Limited and Contributors.
std::vector< float > GetQuantizationScales() const
Definition: Tensor.cpp:453
bool HasMultipleQuantizationScales() const
Definition: Tensor.hpp:201
bool GetDimensionSpecificity(unsigned int i) const
Gets information about if the dimension size has been specified or not.
Definition: Tensor.cpp:211
bool operator==(const TensorShape &other) const
Equality comparison operator.
Definition: Tensor.cpp:160
TensorShape()
Empty (invalid) constructor.
Definition: Tensor.cpp:25
TensorInfo()
Empty (invalid) constructor.
Definition: Tensor.cpp:341
DataType
Definition: Types.hpp:35
int32_t GetQuantizationOffset() const
Definition: Tensor.cpp:480
float GetQuantizationScale() const
Definition: Tensor.cpp:463
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
void SetQuantizationScale(float scale)
Definition: Tensor.cpp:475
#define ARMNN_ASSERT(COND)
Definition: Assert.hpp:14
MemoryType m_MemoryArea
Definition: Tensor.hpp:312
const TensorInfo & GetInfo() const
Definition: Tensor.hpp:295
#define CHECK_LOCATION()
Definition: Exceptions.hpp:209
TensorInfo & operator=(const TensorInfo &other)
Definition: Tensor.cpp:407
void SetQuantizationDim(const Optional< unsigned int > &quantizationDim)
Definition: Tensor.cpp:501
bool operator==(const TensorInfo &other) const
Definition: Tensor.cpp:416
bool operator!=(const TensorInfo &other) const
Definition: Tensor.cpp:424
BaseTensor()
Empty (invalid) constructor.
Definition: Tensor.cpp:526
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
Definition: Tensor.cpp:174
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
void SetConstant(const bool IsConstant=true)
Marks the data corresponding to this tensor info as constant.
Definition: Tensor.cpp:516
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
Definition: NumericCast.hpp:35
void SetQuantizationOffset(int32_t offset)
Definition: Tensor.cpp:491
void SetQuantizationScales(const std::vector< float > &scales)
Definition: Tensor.cpp:458
bool IsAtLeastOneDimensionSpecified() const
Checks if there is at least one dimension specified.
Definition: Tensor.cpp:257
bool IsQuantized() const
Definition: Tensor.cpp:506
constexpr unsigned int MaxNumOfTensorDimensions
Definition: Types.hpp:18
unsigned int GetNumElements() const
Definition: Tensor.hpp:196
constexpr unsigned int GetDataTypeSize(DataType dataType)
Definition: TypesUtils.hpp:151