• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright © 2017,2022-2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 #pragma once
6 
7 #include "Exceptions.hpp"
8 #include "Optional.hpp"
9 #include "Types.hpp"
10 
11 #include <stdint.h>
12 #include <array>
13 #include <initializer_list>
14 #include <vector>
15 #include <utility>
16 
17 namespace armnn
18 {
19 
20 class TensorShape
21 {
22 public:
23     /// Empty (invalid) constructor.
24     TensorShape();
25 
26     /// Constructor for TensorShape
27     /// @param numDimensions - Tensor rank.
28     /// @param initDimensionsSpecificity (optional) - value to initialize the specificity of each dimension size.
29     explicit TensorShape(unsigned int numDimensions, bool initDimensionsSpecificity = true);
30 
31     /// Constructor for TensorShape
32     /// @param numDimensions - Tensor rank.
33     /// @param dimensionSizes - Size of each of dimension.
34     TensorShape(unsigned int numDimensions, const unsigned int* dimensionSizes);
35 
36     /// Constructor for TensorShape
37     /// @param dimensionSizeList - Size of each of dimension.
38     TensorShape(std::initializer_list<unsigned int> dimensionSizeList);
39 
40     /// Copy Constructor for TensorShape
41     /// @param other - TensorShape to copy from.
42     TensorShape(const TensorShape& other);
43 
44     /// Constructor for TensorShape
45     /// @param numDimensions - Tensor rank.
46     /// @param dimensionSizes - Size of each of dimension.
47     /// @param dimensionsSpecificity - Flags to indicate which dimension has its size specified.
48     TensorShape(unsigned int numDimensions, const unsigned int* dimensionSizes, const bool* dimensionsSpecificity);
49 
50     /// Constructor for TensorShape
51     /// @param dimensionSizeList - Size of each of dimension.
52     /// @param dimensionsSpecificityList - Flags to indicate which dimension size is specified.
53     TensorShape(std::initializer_list<unsigned int> dimensionSizeList,
54                 std::initializer_list<bool> dimensionsSpecificityList);
55 
56     /// Constructor for TensorShape
57     /// @param dimensionality - Parameter to indicate if the Tensor is a Scalar, a Tensor of known dimensionality
58     /// or a Tensor of unknown dimensionality.
59     explicit TensorShape(Dimensionality dimensionality);
60 
61     /// Assignation function
62     /// @param other - TensorShape to copy from.
63     TensorShape& operator=(const TensorShape& other);
64 
65     /// Read only operator
66     /// @param i - Dimension index.
67     unsigned int operator[](unsigned int i) const;
68 
69     /// Read and write operator
70     /// @param i - Dimension index.
71     unsigned int& operator[](unsigned int i);
72 
73     /// Equality comparison operator
74     /// @param other - TensorShape to compare with.
75     bool operator==(const TensorShape& other) const;
76 
77     /// Inequality comparison operator
78     /// @param other - TensorShape to compare with.
79     bool operator!=(const TensorShape& other) const;
80 
81     /// Function that returns the tensor rank.
82     /// @return - Tensor rank.
83     unsigned int GetNumDimensions() const;
84 
85     /// Function that calculates the tensor elements by multiplying all dimension size which are Specified.
86     /// @return - Total number of elements in the tensor.
87     unsigned int GetNumElements() const;
88 
89     /// Function that returns the tensor type.
90     /// @return - Parameter to indicate if the Tensor is a scalar, a Tensor of known dimensionality or
91     /// a Tensor of unknown dimensionality
GetDimensionality() const92     Dimensionality GetDimensionality() const { return m_Dimensionality; }
93 
94     /// Gets information about if the dimension size has been specified or not
95     /// @param i - Dimension index.
96     /// @return - Flag to indicate if the dimension "i" has a specified size.
97     bool GetDimensionSpecificity(unsigned int i) const;
98 
99     /// Sets the tensor rank and therefore the Dimensionality is set to Specified if it was not.
100     /// @param numDimensions - Tensor rank.
101     /// @param initDimensionsSpecificity (optional) - value to initialize the specificity of each dimension size.
102     void SetNumDimensions(unsigned int numDimensions, bool initDimensionsSpecificity = false);
103 
104     /// Sets the size of the indicated dimension and Specificity for that dimension is set to true.
105     /// @param i - Dimension index.
106     /// @param dimensionSize - size of one dimension.
107     void SetDimensionSize(unsigned int i, unsigned int dimensionSize);
108 
109     /// Checks if there is at least one dimension not specified. AND of all array elements.
110     /// @return - True when all dimension sizes are specified. False when at least one dimension size is not specified.
111     bool AreAllDimensionsSpecified() const;
112 
113     /// Checks if there is at least one dimension specified. OR of all array elements.
114     /// @return - True at least one dimension sizes is specified. False when all dimension sizes are not specified.
115     bool IsAtLeastOneDimensionSpecified() const;
116 
117 private:
118     /// Array of the dimension sizes.
119     std::array<unsigned int, MaxNumOfTensorDimensions> m_Dimensions{};
120 
121     /// Array of flags to indicate if the size of each of the dimensions is specified or not
122     std::array<bool, MaxNumOfTensorDimensions> m_DimensionsSpecificity = { {true} };
123 
124     /// Tensor rank
125     unsigned int m_NumDimensions{};
126 
127     /// Tensor type: Specified, NotSpecified or Scalar.
128     Dimensionality m_Dimensionality = Dimensionality::Specified;
129 
130     /// Checks if the dimension index given is within range.
131     /// @param i - Dimension index.
132     void CheckDimensionIndex(unsigned int i) const;
133 
134     /// Checks if the tensor rank given is within range.
135     /// @param numDimensions - Tensor rank.
136     static void CheckValidNumDimensions(unsigned int numDimensions) ;
137 
138     /// Checks if the size of the dimension index given is specified.
139     /// @param i - Dimension index.
140     void CheckDimensionSpecified(unsigned int i) const;
141 
142     /// Checks if this is a scalar.
143     void CheckScalar() const;
144 
145     /// Checks if the number of dimensions is unknown, i.e. rank is unspecified.
146     void CheckUnspecifiedNumDimensions() const;
147 
148     /// Checks if the number of dimensions is known, i.e. rank is specified.
149     void CheckSpecifiedNumDimensions() const;
150 };
151 
152 class TensorInfo
153 {
154 public:
155     /// Empty (invalid) constructor.
156     TensorInfo();
157 
158     TensorInfo(const TensorShape& shape,
159                DataType dataType,
160                float quantizationScale = 1.0f,
161                int32_t quantizationOffset = 0,
162                bool isConstant = false);
163 
164     TensorInfo(unsigned int numDimensions,
165                const unsigned int* dimensionSizes,
166                DataType dataType,
167                float quantizationScale = 1.0f,
168                int32_t quantizationOffset = 0,
169                bool isConstant = false);
170 
171     TensorInfo(const TensorShape& shape,
172                DataType dataType,
173                const std::vector<float>& quantizationScales,
174                unsigned int quantizationDim,
175                bool isConstant = false);
176 
177     TensorInfo(unsigned int numDimensions,
178                const unsigned int* dimensionSizes,
179                DataType dataType,
180                const std::vector<float>& quantizationScales,
181                unsigned int quantizationDim,
182                bool isConstant = false);
183 
184     TensorInfo(const TensorInfo& other);
185 
186     TensorInfo& operator=(const TensorInfo& other);
187 
188     bool operator==(const TensorInfo& other) const;
189     bool operator!=(const TensorInfo& other) const;
190 
GetShape() const191     const TensorShape& GetShape() const              { return m_Shape; }
GetShape()192     TensorShape& GetShape()                          { return m_Shape; }
SetShape(const TensorShape & newShape)193     void SetShape(const TensorShape& newShape)       { m_Shape = newShape; }
194 
GetNumDimensions() const195     unsigned int GetNumDimensions() const            { return m_Shape.GetNumDimensions(); }
GetNumElements() const196     unsigned int GetNumElements() const              { return m_Shape.GetNumElements(); }
197 
GetDataType() const198     DataType GetDataType() const                     { return m_DataType; }
SetDataType(DataType type)199     void SetDataType(DataType type)                  { m_DataType = type; }
200 
HasMultipleQuantizationScales() const201     bool HasMultipleQuantizationScales() const       { return m_Quantization.m_Scales.size() > 1; }
202 
203     bool HasPerAxisQuantization() const;
204 
205     std::vector<float> GetQuantizationScales() const;
206     void SetQuantizationScales(const std::vector<float>& scales);
207 
208     float GetQuantizationScale() const;
209     void SetQuantizationScale(float scale);
210 
211     int32_t GetQuantizationOffset() const;
212     void SetQuantizationOffset(int32_t offset);
213 
214     Optional<unsigned int> GetQuantizationDim() const;
215     void SetQuantizationDim(const Optional<unsigned int>& quantizationDim);
216 
217     bool IsQuantized() const;
218 
219     bool IsConstant() const;
220 
221     /// Marks the data corresponding to this tensor info as constant.
222     ///
223     /// @details: This can allow further optimization on execution
224     /// @Note: The user has to ensure that the underlying data actually is constant.
225     void SetConstant(const bool IsConstant=true);
226 
227     /// Check that the types are the same and, if quantize, that the quantization parameters are the same.
228     bool IsTypeSpaceMatch(const TensorInfo& other) const;
229 
230     unsigned int GetNumBytes() const;
231 
232 private:
233     TensorShape m_Shape;
234     DataType    m_DataType;
235     bool        m_IsConstant;
236 
237     /// Vectors of scale and offset are used for per-axis quantization.
238     struct Quantization
239     {
Quantizationarmnn::TensorInfo::Quantization240         Quantization()
241             : m_Scales{}
242             , m_Offset(EmptyOptional())
243             , m_QuantizationDim(EmptyOptional()) {}
244 
Quantizationarmnn::TensorInfo::Quantization245         Quantization(const Quantization& other)
246             : m_Scales(other.m_Scales)
247             , m_Offset(other.m_Offset)
248             , m_QuantizationDim(other.m_QuantizationDim) {}
249 
operator ==armnn::TensorInfo::Quantization250         bool operator==(const Quantization& other) const
251         {
252             return ((m_Scales == other.m_Scales) && (m_Offset == other.m_Offset) &&
253                 (m_QuantizationDim == other.m_QuantizationDim));
254         }
255 
operator =armnn::TensorInfo::Quantization256         Quantization& operator=(const Quantization& other)
257         {
258             if(this != &other)
259             {
260                 m_Scales = other.m_Scales;
261                 m_Offset = other.m_Offset;
262                 m_QuantizationDim = other.m_QuantizationDim;
263             }
264             return *this;
265         }
266 
267         std::vector<float>     m_Scales;
268         Optional<int32_t>      m_Offset;
269         Optional<unsigned int> m_QuantizationDim;
270 
271     } m_Quantization;
272 };
273 
274 using BindingPointInfo = std::pair<armnn::LayerBindingId, armnn::TensorInfo>;
275 
276 template<typename MemoryType>
277 class BaseTensor
278 {
279 public:
280     /// Empty (invalid) constructor.
281     BaseTensor();
282 
283     /// Constructor from a raw memory pointer.
284     /// @param memoryArea - Region of CPU-addressable memory where tensor data will be stored. Must be valid while
285     /// workloads are on the fly. Tensor instances do not claim ownership of referenced memory regions, that is,
286     /// no attempt will be made by ArmNN to free these memory regions automatically.
287     BaseTensor(const TensorInfo& info, MemoryType memoryArea);
288 
289     /// Tensors are copyable.
290     BaseTensor(const BaseTensor& other);
291 
292     /// Tensors are copyable.
293     BaseTensor& operator=(const BaseTensor&);
294 
GetInfo() const295     const TensorInfo& GetInfo() const { return m_Info; }
GetInfo()296     TensorInfo& GetInfo() { return m_Info; }
GetShape() const297     const TensorShape& GetShape() const { return m_Info.GetShape(); }
GetShape()298     TensorShape& GetShape() { return m_Info.GetShape(); }
299 
GetDataType() const300     DataType GetDataType() const { return m_Info.GetDataType(); }
GetNumDimensions() const301     unsigned int GetNumDimensions() const { return m_Info.GetNumDimensions(); }
GetNumBytes() const302     unsigned int GetNumBytes() const { return m_Info.GetNumBytes(); }
GetNumElements() const303     unsigned int GetNumElements() const { return m_Info.GetNumElements(); }
304 
GetMemoryArea() const305     MemoryType GetMemoryArea() const { return m_MemoryArea; }
306 
307 protected:
308     /// Protected destructor to stop users from making these
309     /// (could still new one on the heap and then leak it...)
~BaseTensor()310     ~BaseTensor() {}
311 
312     MemoryType m_MemoryArea;
313 
314 private:
315     TensorInfo m_Info;
316 };
317 
318 /// A tensor defined by a TensorInfo (shape and data type) and a mutable backing store.
319 class Tensor : public BaseTensor<void*>
320 {
321 public:
322     /// Brings in the constructors and assignment operator.
323     using BaseTensor<void*>::BaseTensor;
324 };
325 
326 /// A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
327 class ConstTensor : public BaseTensor<const void*>
328 {
329 public:
330     /// Brings in the constructors and assignment operator.
331     using BaseTensor<const void*>::BaseTensor;
ConstTensor()332     ConstTensor() : BaseTensor<const void*>()
333     {
334         this->GetInfo().SetConstant();
335     }
336 
337     /// ConstTensor implicitly constructed from non-const Tensor.
338     ///
339     /// @param other - reference to a constant Tensor.
340     ///
341     /// @throws InvalidArgumentException when Tensor parameter TensorInfo is non-constant.
ConstTensor(const Tensor & other)342     ConstTensor(const Tensor& other) : BaseTensor<const void*>(other.GetInfo(), other.GetMemoryArea())
343     {
344         if (!this->GetInfo().IsConstant())
345         {
346             throw InvalidArgumentException("Invalid attempt to construct ConstTensor "
347                                            "from Tensor due to non-constant TensorInfo");
348         }
349     }
350 
351     /// Constructor from a backing container.
352     ///
353     /// @param container - An stl-like container type which implements data() and size() methods.
354     /// Presence of data() and size() is a strong indicator of the continuous memory layout of the container,
355     /// which is a requirement for Tensor data. Tensor instances do not claim ownership of referenced memory regions,
356     /// that is, no attempt will be made by ArmNN to free these memory regions automatically.
357     ///
358     /// @throws InvalidArgumentException when isConstant parameter of input TensorInfo is false.
359     template < template<typename, typename...> class ContainerType, typename T, typename...ContainerArgs >
ConstTensor(const TensorInfo & info,const ContainerType<T,ContainerArgs...> & container)360     ConstTensor(const TensorInfo& info, const ContainerType<T, ContainerArgs...>& container)
361         : BaseTensor<const void*>(info, container.data())
362     {
363         if (!this->GetInfo().IsConstant())
364         {
365             throw InvalidArgumentException("Invalid attempt to construct ConstTensor from non-constant TensorInfo.");
366         }
367         if (container.size() * sizeof(T) != info.GetNumBytes())
368         {
369             throw InvalidArgumentException("Container size is not correct");
370         }
371     }
372 
373     /// ConstTensor constructed from TensorInfo and MemoryType template (a raw memory pointer).
374     ///
375     /// @param info - reference to a constant TensorInfo.
376     /// @param memoryArea - Region of CPU-addressable memory where tensor data will be stored. Must be valid while
377     /// workloads are on the fly. Tensor instances do not claim ownership of referenced memory regions, that is,
378     /// no attempt will be made by ArmNN to free these memory regions automatically.
379     ///
380     /// @throws InvalidArgumentException when TensorInfo isConstant parameter is false.
381     template<typename MemoryType>
ConstTensor(const TensorInfo & info,MemoryType memoryArea)382     ConstTensor(const TensorInfo& info, MemoryType memoryArea)
383         : BaseTensor<const void*>(info, memoryArea)
384     {
385         if (!this->GetInfo().IsConstant())
386         {
387             throw InvalidArgumentException("Invalid attempt to construct ConstTensor from non-constant TensorInfo.");
388         }
389     }
390 };
391 
392 using InputTensors = std::vector<std::pair<LayerBindingId, class ConstTensor>>;
393 using OutputTensors = std::vector<std::pair<LayerBindingId, class Tensor>>;
394 
395 } // namespace armnn
396