ArmNN
 25.11
Loading...
Searching...
No Matches
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"
10
13
14#include <iostream>
15
16#include <sstream>
17
18namespace armnn
19{
20
21// ---
22// --- TensorShape
23// ---
24
26 : m_NumDimensions(0), m_Dimensionality(Dimensionality::Specified)
27{
28}
29
30TensorShape::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
40TensorShape::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
54TensorShape::TensorShape(std::initializer_list<unsigned int> dimensionSizeList)
55 : TensorShape(armnn::numeric_cast<unsigned int>(dimensionSizeList.size()), dimensionSizeList.begin())
56{
57}
58
59TensorShape::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
80TensorShape::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
135unsigned 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
145unsigned 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
160bool 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
169bool TensorShape::operator!=(const TensorShape& other) const
170{
171 return !(*this == other);
172}
173
175{
176 CheckUnspecifiedNumDimensions();
177
178 return m_NumDimensions;
179}
180
181unsigned 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
212{
213 CheckUnspecifiedNumDimensions();
214 CheckDimensionIndex(i);
215
216 return m_DimensionsSpecificity[i];
217}
218
219void 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
232void 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
273void 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
283void 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 }
296
297void 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
307void 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
317void 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
327void 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
359TensorInfo::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);
382}
383
384TensorInfo::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);
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
414bool 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
422bool TensorInfo::operator!=(const TensorInfo& other) const
423{
424 return !(*this == other);
425}
426
427unsigned int TensorInfo::GetNumBytes() const
428{
429 return GetDataTypeSize(m_DataType) * GetNumElements();
430}
431
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
451std::vector<float> TensorInfo::GetQuantizationScales() const
452{
453 return m_Quantization.m_Scales;
454}
455
456void 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
519{
520 m_IsConstant = IsConstant;
521}
522
523// ---
524// --- BaseTensor
525// ---
526
527template<typename MemoryType>
532
533template<typename MemoryType>
535 : m_MemoryArea(memoryArea)
536 , m_Info(info)
537{
538}
539
540template<typename MemoryType>
542 : m_MemoryArea(other.m_MemoryArea)
543 , m_Info(other.GetInfo())
544{
545}
546
547template<typename MemoryType>
549{
550 m_Info = other.m_Info;
552 return *this;
553}
554
555// Explicit instantiations.
556template class BaseTensor<const void*>;
557template class BaseTensor<void*>;
558
559} // namespace armnn
#define CHECK_LOCATION()
BaseTensor & operator=(const BaseTensor &)
Tensors are copyable.
Definition Tensor.cpp:548
MemoryType m_MemoryArea
Definition Tensor.hpp:314
BaseTensor()
Empty (invalid) constructor.
Definition Tensor.cpp:528
float GetQuantizationScale() const
Definition Tensor.cpp:461
void SetQuantizationScales(const std::vector< float > &scales)
Definition Tensor.cpp:456
TensorInfo()
Empty (invalid) constructor.
Definition Tensor.cpp:341
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
bool operator!=(const TensorInfo &other) const
Definition Tensor.cpp:422
void SetQuantizationDim(const Optional< unsigned int > &quantizationDim)
Definition Tensor.cpp:503
bool operator==(const TensorInfo &other) const
Definition Tensor.cpp:414
void SetQuantizationOffset(int32_t offset)
Definition Tensor.cpp:493
void SetQuantizationScale(float scale)
Definition Tensor.cpp:477
int32_t GetQuantizationOffset() const
Definition Tensor.cpp:482
bool IsQuantized() const
Definition Tensor.cpp:508
unsigned int GetNumElements() const
Definition Tensor.hpp:198
Optional< unsigned int > GetQuantizationDim() const
Definition Tensor.cpp:498
std::vector< float > GetQuantizationScales() const
Definition Tensor.cpp:451
void SetConstant(const bool IsConstant=true)
Marks the data corresponding to this tensor info as constant.
Definition Tensor.cpp:518
bool IsConstant() const
Definition Tensor.cpp:513
bool HasPerAxisQuantization() const
Definition Tensor.cpp:446
unsigned int GetNumBytes() const
Definition Tensor.cpp:427
TensorInfo & operator=(const TensorInfo &other)
Definition Tensor.cpp:405
bool HasMultipleQuantizationScales() const
Definition Tensor.hpp:203
bool operator==(const TensorShape &other) const
Equality comparison operator.
Definition Tensor.cpp:160
TensorShape & operator=(const TensorShape &other)
Assignation function.
Definition Tensor.cpp:124
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
Definition Tensor.cpp:174
bool IsAtLeastOneDimensionSpecified() const
Checks if there is at least one dimension specified.
Definition Tensor.cpp:257
bool GetDimensionSpecificity(unsigned int i) const
Gets information about if the dimension size has been specified or not.
Definition Tensor.cpp:211
unsigned int operator[](unsigned int i) const
Read only operator.
Definition Tensor.cpp:135
TensorShape()
Empty (invalid) constructor.
Definition Tensor.cpp:25
bool operator!=(const TensorShape &other) const
Inequality comparison operator.
Definition Tensor.cpp:169
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
unsigned int GetNumElements() const
Function that calculates the tensor elements by multiplying all dimension size which are Specified.
Definition Tensor.cpp:181
bool AreAllDimensionsSpecified() const
Checks if there is at least one dimension not specified.
Definition Tensor.cpp:241
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
Copyright (c) 2021 ARM Limited and Contributors.
Optional< T > MakeOptional(Args &&... args)
Utility template that constructs an object of type T in-place and wraps it inside an Optional<T> obje...
Definition Optional.hpp:305
constexpr bool IsQuantizedType()
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
constexpr unsigned int GetDataTypeSize(DataType dataType)
Dimensionality
Definition Types.hpp:174
constexpr unsigned int MaxNumOfTensorDimensions
Definition Types.hpp:31
DataType
Definition Types.hpp:49