• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
12 #include <armnn/utility/NumericCast.hpp>
13 
14 #include <iostream>
15 
16 #include <sstream>
17 
18 namespace armnn
19 {
20 
21 // ---
22 // --- TensorShape
23 // ---
24 
TensorShape()25 TensorShape::TensorShape()
26  : m_NumDimensions(0), m_Dimensionality(Dimensionality::Specified)
27 {
28 }
29 
TensorShape(unsigned int numDimensions,bool initDimensionsSpecificity)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 
TensorShape(const unsigned int numDimensions,const unsigned int * const dimensionSizes)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 
TensorShape(std::initializer_list<unsigned int> dimensionSizeList)54 TensorShape::TensorShape(std::initializer_list<unsigned int> dimensionSizeList)
55  : TensorShape(armnn::numeric_cast<unsigned int>(dimensionSizeList.size()), dimensionSizeList.begin())
56 {
57 }
58 
TensorShape(unsigned int numDimensions,const unsigned int * const dimensionSizes,const bool * const dimensionsSpecificity)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 
TensorShape(std::initializer_list<unsigned int> dimensionSizeList,std::initializer_list<bool> dimensionsSpecificityList)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 
TensorShape(Dimensionality dimensionality)92 TensorShape::TensorShape(Dimensionality dimensionality)
93 : m_Dimensionality(dimensionality)
94 {
95     switch (dimensionality)
96     {
97         case Dimensionality::Specified:
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;
101         case Dimensionality::NotSpecified:
102             m_NumDimensions = 0;
103             m_Dimensions = {0};
104             m_DimensionsSpecificity = {false};
105             break;
106         case Dimensionality::Scalar:
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 
TensorShape(const TensorShape & other)116 TensorShape::TensorShape(const TensorShape& other)
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 
operator =(const TensorShape & other)124 TensorShape& TensorShape::operator =(const TensorShape& other)
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
operator [](unsigned int i) const135 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
operator [](unsigned int i)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 
operator ==(const TensorShape & other) const160 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 
operator !=(const TensorShape & other) const169 bool TensorShape::operator!=(const TensorShape& other) const
170 {
171     return !(*this == other);
172 }
173 
GetNumDimensions() const174 unsigned int TensorShape::GetNumDimensions() const
175 {
176     CheckUnspecifiedNumDimensions();
177 
178     return m_NumDimensions;
179 }
180 
GetNumElements() const181 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 
GetDimensionSpecificity(unsigned int i) const211 bool TensorShape:: GetDimensionSpecificity(unsigned int i) const
212 {
213     CheckUnspecifiedNumDimensions();
214     CheckDimensionIndex(i);
215 
216     return m_DimensionsSpecificity[i];
217 }
218 
SetNumDimensions(unsigned int numDimensions,bool initDimensionsSpecificity)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 
SetDimensionSize(unsigned int i,unsigned int dimensionSize)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 
AreAllDimensionsSpecified() const241 bool TensorShape::AreAllDimensionsSpecified() const
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 
IsAtLeastOneDimensionSpecified() const257 bool TensorShape::IsAtLeastOneDimensionSpecified() const
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 
CheckDimensionIndex(unsigned int i) const273 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 
CheckValidNumDimensions(unsigned int numDimensions)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 
CheckDimensionSpecified(unsigned int i) const297 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 
CheckScalar() const307 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 
CheckUnspecifiedNumDimensions() const317 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 
CheckSpecifiedNumDimensions() const327 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 
TensorInfo()341 TensorInfo::TensorInfo()
342 : m_DataType(DataType::Float32)
343 {
344 }
345 
TensorInfo(const TensorShape & shape,DataType dataType,float quantizationScale,int32_t quantizationOffset)346 TensorInfo::TensorInfo(const TensorShape& shape,
347                        DataType dataType,
348                        float quantizationScale,
349                        int32_t quantizationOffset)
350     : m_Shape(shape)
351     , m_DataType(dataType)
352 {
353     SetQuantizationScale(quantizationScale);
354     SetQuantizationOffset(quantizationOffset);
355 }
356 
TensorInfo(unsigned int numDimensions,const unsigned int * dimensionSizes,DataType dataType,float quantizationScale,int32_t quantizationOffset)357 TensorInfo::TensorInfo(unsigned int numDimensions,
358                        const unsigned int* dimensionSizes,
359                        DataType dataType,
360                        float quantizationScale,
361                        int32_t quantizationOffset)
362     : m_Shape(numDimensions, dimensionSizes)
363     , m_DataType(dataType)
364 {
365     SetQuantizationScale(quantizationScale);
366     SetQuantizationOffset(quantizationOffset);
367 }
368 
TensorInfo(const TensorShape & shape,DataType dataType,const std::vector<float> & quantizationScales,unsigned int quantizationDim)369 TensorInfo::TensorInfo(const TensorShape& shape,
370                        DataType dataType,
371                        const std::vector<float>& quantizationScales,
372                        unsigned int quantizationDim)
373     : m_Shape(shape)
374     , m_DataType(dataType)
375 {
376     SetQuantizationScales(quantizationScales);
377     SetQuantizationDim(MakeOptional<unsigned int>(quantizationDim));
378 }
379 
TensorInfo(unsigned int numDimensions,const unsigned int * dimensionSizes,DataType dataType,const std::vector<float> & quantizationScales,unsigned int quantizationDim)380 TensorInfo::TensorInfo(unsigned int numDimensions,
381                        const unsigned int* dimensionSizes,
382                        DataType dataType,
383                        const std::vector<float>& quantizationScales,
384                        unsigned int quantizationDim)
385     : m_Shape(numDimensions, dimensionSizes)
386     , m_DataType(dataType)
387 {
388     SetQuantizationScales(quantizationScales);
389     SetQuantizationDim(MakeOptional<unsigned int>(quantizationDim));
390 }
391 
TensorInfo(const TensorInfo & other)392 TensorInfo::TensorInfo(const TensorInfo& other)
393 : m_Shape(other.m_Shape)
394 , m_DataType(other.m_DataType)
395 , m_Quantization(other.m_Quantization)
396 {}
397 
operator =(const TensorInfo & other)398 TensorInfo& TensorInfo::operator=(const TensorInfo& other)
399 {
400     m_Shape = other.m_Shape;
401     m_DataType = other.m_DataType;
402     m_Quantization = other.m_Quantization;
403     return *this;
404 }
405 
operator ==(const TensorInfo & other) const406 bool TensorInfo::operator==(const TensorInfo& other) const
407 {
408     return ((m_Shape == other.m_Shape) &&
409             (m_DataType == other.m_DataType) &&
410             (m_Quantization == other.m_Quantization));
411 }
412 
operator !=(const TensorInfo & other) const413 bool TensorInfo::operator!=(const TensorInfo& other) const
414 {
415     return !(*this == other);
416 }
417 
GetNumBytes() const418 unsigned int TensorInfo::GetNumBytes() const
419 {
420     return GetDataTypeSize(m_DataType) * GetNumElements();
421 }
422 
IsTypeSpaceMatch(const TensorInfo & other) const423 bool TensorInfo::IsTypeSpaceMatch(const TensorInfo& other) const
424 {
425     bool match = true;
426 
427     match &= m_DataType == other.m_DataType;
428 
429     if (IsQuantized() && !HasMultipleQuantizationScales())
430     {
431         match &= GetQuantizationScale() == other.GetQuantizationScale() &&
432                  GetQuantizationOffset() == other.GetQuantizationOffset();
433     }
434     return match;
435 }
436 
HasPerAxisQuantization() const437 bool TensorInfo::HasPerAxisQuantization() const
438 {
439     return HasMultipleQuantizationScales() || m_Quantization.m_QuantizationDim.has_value();
440 }
441 
GetQuantizationScales() const442 std::vector<float> TensorInfo::GetQuantizationScales() const
443 {
444     return m_Quantization.m_Scales;
445 }
446 
SetQuantizationScales(const std::vector<float> & scales)447 void TensorInfo::SetQuantizationScales(const std::vector<float>& scales)
448 {
449     m_Quantization.m_Scales = scales;
450 }
451 
GetQuantizationScale() const452 float TensorInfo::GetQuantizationScale() const
453 {
454     if (m_Quantization.m_Scales.empty())
455     {
456         // NOTE: old default for backward compatibility
457         return 1.0f;
458     }
459 
460     ARMNN_ASSERT(!HasMultipleQuantizationScales());
461     return m_Quantization.m_Scales[0];
462 }
463 
SetQuantizationScale(float scale)464 void TensorInfo::SetQuantizationScale(float scale)
465 {
466     m_Quantization.m_Scales = { scale };
467 }
468 
GetQuantizationOffset() const469 int32_t TensorInfo::GetQuantizationOffset() const
470 {
471     if (!m_Quantization.m_Offset.has_value())
472     {
473         // NOTE: old default for backward compatibility
474         return 0;
475     }
476 
477     return m_Quantization.m_Offset.value();
478 }
479 
SetQuantizationOffset(int32_t offset)480 void TensorInfo::SetQuantizationOffset(int32_t offset)
481 {
482     m_Quantization.m_Offset = MakeOptional<int32_t>(offset);
483 }
484 
GetQuantizationDim() const485 Optional<unsigned int> TensorInfo::GetQuantizationDim() const
486 {
487     return m_Quantization.m_QuantizationDim;
488 }
489 
SetQuantizationDim(const Optional<unsigned int> & quantizationDim)490 void TensorInfo::SetQuantizationDim(const Optional<unsigned int>& quantizationDim)
491 {
492     m_Quantization.m_QuantizationDim = quantizationDim;
493 }
494 
IsQuantized() const495 bool TensorInfo::IsQuantized() const
496 {
497     return IsQuantizedType(m_DataType);
498 }
499 
500 // ---
501 // --- BaseTensor
502 // ---
503 
504 template<typename MemoryType>
BaseTensor()505 BaseTensor<MemoryType>::BaseTensor()
506  : m_MemoryArea(nullptr)
507 {
508 }
509 
510 template<typename MemoryType>
BaseTensor(const TensorInfo & info,MemoryType memoryArea)511 BaseTensor<MemoryType>::BaseTensor(const TensorInfo& info, MemoryType memoryArea)
512  : m_MemoryArea(memoryArea)
513  , m_Info(info)
514 {
515 }
516 
517 template<typename MemoryType>
BaseTensor(const BaseTensor<MemoryType> & other)518 BaseTensor<MemoryType>::BaseTensor(const BaseTensor<MemoryType>& other)
519  : m_MemoryArea(other.m_MemoryArea)
520  , m_Info(other.GetInfo())
521 {
522 }
523 
524 template<typename MemoryType>
operator =(const BaseTensor<MemoryType> & other)525 BaseTensor<MemoryType>& BaseTensor<MemoryType>::operator =(const BaseTensor<MemoryType>& other)
526 {
527     m_Info = other.m_Info;
528     m_MemoryArea = other.m_MemoryArea;
529     return *this;
530 }
531 
532 // Explicit instantiations.
533 template class BaseTensor<const void*>;
534 template class BaseTensor<void*>;
535 
536 } // namespace armnn
537