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