• 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), m_IsConstant(false)
343 {
344 }
345 
TensorInfo(const TensorShape & shape,DataType dataType,float quantizationScale,int32_t quantizationOffset,bool isConstant)346 TensorInfo::TensorInfo(const TensorShape& shape,
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 
TensorInfo(unsigned int numDimensions,const unsigned int * dimensionSizes,DataType dataType,float quantizationScale,int32_t quantizationOffset,bool isConstant)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 
TensorInfo(const TensorShape & shape,DataType dataType,const std::vector<float> & quantizationScales,unsigned int quantizationDim,bool isConstant)371 TensorInfo::TensorInfo(const TensorShape& shape,
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 
TensorInfo(unsigned int numDimensions,const unsigned int * dimensionSizes,DataType dataType,const std::vector<float> & quantizationScales,unsigned int quantizationDim,bool isConstant)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 
TensorInfo(const TensorInfo & other)398 TensorInfo::TensorInfo(const TensorInfo& other)
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 
operator =(const TensorInfo & other)405 TensorInfo& TensorInfo::operator=(const TensorInfo& other)
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 
operator ==(const TensorInfo & other) const414 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 
operator !=(const TensorInfo & other) const422 bool TensorInfo::operator!=(const TensorInfo& other) const
423 {
424     return !(*this == other);
425 }
426 
GetNumBytes() const427 unsigned int TensorInfo::GetNumBytes() const
428 {
429     return GetDataTypeSize(m_DataType) * GetNumElements();
430 }
431 
IsTypeSpaceMatch(const TensorInfo & other) const432 bool TensorInfo::IsTypeSpaceMatch(const TensorInfo& other) const
433 {
434     bool match = true;
435 
436     match &= m_DataType == other.m_DataType;
437 
438     if (IsQuantized() && !HasMultipleQuantizationScales())
439     {
440         match &= GetQuantizationScale() == other.GetQuantizationScale() &&
441                  GetQuantizationOffset() == other.GetQuantizationOffset();
442     }
443     return match;
444 }
445 
HasPerAxisQuantization() const446 bool TensorInfo::HasPerAxisQuantization() const
447 {
448     return HasMultipleQuantizationScales() || m_Quantization.m_QuantizationDim.has_value();
449 }
450 
GetQuantizationScales() const451 std::vector<float> TensorInfo::GetQuantizationScales() const
452 {
453     return m_Quantization.m_Scales;
454 }
455 
SetQuantizationScales(const std::vector<float> & scales)456 void TensorInfo::SetQuantizationScales(const std::vector<float>& scales)
457 {
458     m_Quantization.m_Scales = scales;
459 }
460 
GetQuantizationScale() const461 float TensorInfo::GetQuantizationScale() const
462 {
463     if (m_Quantization.m_Scales.empty())
464     {
465         // NOTE: old default for backward compatibility
466         return 1.0f;
467     }
468 
469     ARMNN_ASSERT(!HasMultipleQuantizationScales());
470     return m_Quantization.m_Scales[0];
471 }
472 
SetQuantizationScale(float scale)473 void TensorInfo::SetQuantizationScale(float scale)
474 {
475     m_Quantization.m_Scales = { scale };
476 }
477 
GetQuantizationOffset() const478 int32_t TensorInfo::GetQuantizationOffset() const
479 {
480     if (!m_Quantization.m_Offset.has_value())
481     {
482         // NOTE: old default for backward compatibility
483         return 0;
484     }
485 
486     return m_Quantization.m_Offset.value();
487 }
488 
SetQuantizationOffset(int32_t offset)489 void TensorInfo::SetQuantizationOffset(int32_t offset)
490 {
491     m_Quantization.m_Offset = MakeOptional<int32_t>(offset);
492 }
493 
GetQuantizationDim() const494 Optional<unsigned int> TensorInfo::GetQuantizationDim() const
495 {
496     return m_Quantization.m_QuantizationDim;
497 }
498 
SetQuantizationDim(const Optional<unsigned int> & quantizationDim)499 void TensorInfo::SetQuantizationDim(const Optional<unsigned int>& quantizationDim)
500 {
501     m_Quantization.m_QuantizationDim = quantizationDim;
502 }
503 
IsQuantized() const504 bool TensorInfo::IsQuantized() const
505 {
506     return IsQuantizedType(m_DataType);
507 }
508 
IsConstant() const509 bool TensorInfo::IsConstant() const
510 {
511     return m_IsConstant;
512 }
513 
SetConstant(const bool IsConstant)514 void TensorInfo::SetConstant(const bool IsConstant)
515 {
516     m_IsConstant = IsConstant;
517 }
518 
519 // ---
520 // --- BaseTensor
521 // ---
522 
523 template<typename MemoryType>
BaseTensor()524 BaseTensor<MemoryType>::BaseTensor()
525  : m_MemoryArea(nullptr)
526 {
527 }
528 
529 template<typename MemoryType>
BaseTensor(const TensorInfo & info,MemoryType memoryArea)530 BaseTensor<MemoryType>::BaseTensor(const TensorInfo& info, MemoryType memoryArea)
531  : m_MemoryArea(memoryArea)
532  , m_Info(info)
533 {
534 }
535 
536 template<typename MemoryType>
BaseTensor(const BaseTensor<MemoryType> & other)537 BaseTensor<MemoryType>::BaseTensor(const BaseTensor<MemoryType>& other)
538  : m_MemoryArea(other.m_MemoryArea)
539  , m_Info(other.GetInfo())
540 {
541 }
542 
543 template<typename MemoryType>
operator =(const BaseTensor<MemoryType> & other)544 BaseTensor<MemoryType>& BaseTensor<MemoryType>::operator =(const BaseTensor<MemoryType>& other)
545 {
546     m_Info = other.m_Info;
547     m_MemoryArea = other.m_MemoryArea;
548     return *this;
549 }
550 
551 // Explicit instantiations.
552 template class BaseTensor<const void*>;
553 template class BaseTensor<void*>;
554 
555 } // namespace armnn
556