1 // 2 // Copyright © 2017 Arm Ltd. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 // 5 #pragma once 6 7 #include "TensorFwd.hpp" 8 9 #include "Exceptions.hpp" 10 #include "Optional.hpp" 11 #include "Types.hpp" 12 13 #include <array> 14 #include <initializer_list> 15 #include <vector> 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 = 0.0f, 161 int32_t quantizationOffset = 0); 162 163 TensorInfo(unsigned int numDimensions, 164 const unsigned int* dimensionSizes, 165 DataType dataType, 166 float quantizationScale = 0.0f, 167 int32_t quantizationOffset = 0); 168 169 TensorInfo(const TensorShape& shape, 170 DataType dataType, 171 const std::vector<float>& quantizationScales, 172 unsigned int quantizationDim); 173 174 TensorInfo(unsigned int numDimensions, 175 const unsigned int* dimensionSizes, 176 DataType dataType, 177 const std::vector<float>& quantizationScales, 178 unsigned int quantizationDim); 179 180 TensorInfo(const TensorInfo& other); 181 182 TensorInfo& operator=(const TensorInfo& other); 183 184 bool operator==(const TensorInfo& other) const; 185 bool operator!=(const TensorInfo& other) const; 186 GetShape() const187 const TensorShape& GetShape() const { return m_Shape; } GetShape()188 TensorShape& GetShape() { return m_Shape; } SetShape(const TensorShape & newShape)189 void SetShape(const TensorShape& newShape) { m_Shape = newShape; } 190 GetNumDimensions() const191 unsigned int GetNumDimensions() const { return m_Shape.GetNumDimensions(); } GetNumElements() const192 unsigned int GetNumElements() const { return m_Shape.GetNumElements(); } 193 GetDataType() const194 DataType GetDataType() const { return m_DataType; } SetDataType(DataType type)195 void SetDataType(DataType type) { m_DataType = type; } 196 HasMultipleQuantizationScales() const197 bool HasMultipleQuantizationScales() const { return m_Quantization.m_Scales.size() > 1; } 198 199 bool HasPerAxisQuantization() const; 200 201 std::vector<float> GetQuantizationScales() const; 202 void SetQuantizationScales(const std::vector<float>& scales); 203 204 float GetQuantizationScale() const; 205 void SetQuantizationScale(float scale); 206 207 int32_t GetQuantizationOffset() const; 208 void SetQuantizationOffset(int32_t offset); 209 210 Optional<unsigned int> GetQuantizationDim() const; 211 void SetQuantizationDim(const Optional<unsigned int>& quantizationDim); 212 213 bool IsQuantized() const; 214 215 /// Check that the types are the same and, if quantize, that the quantization parameters are the same. 216 bool IsTypeSpaceMatch(const TensorInfo& other) const; 217 218 unsigned int GetNumBytes() const; 219 220 private: 221 TensorShape m_Shape; 222 DataType m_DataType; 223 224 /// Vectors of scale and offset are used for per-axis quantization. 225 struct Quantization 226 { Quantizationarmnn::TensorInfo::Quantization227 Quantization() 228 : m_Scales{} 229 , m_Offset(EmptyOptional()) 230 , m_QuantizationDim(EmptyOptional()) {} 231 Quantizationarmnn::TensorInfo::Quantization232 Quantization(const Quantization& other) 233 : m_Scales(other.m_Scales) 234 , m_Offset(other.m_Offset) 235 , m_QuantizationDim(other.m_QuantizationDim) {} 236 operator ==armnn::TensorInfo::Quantization237 bool operator==(const Quantization& other) const 238 { 239 return ((m_Scales == other.m_Scales) && (m_Offset == other.m_Offset) && 240 (m_QuantizationDim == other.m_QuantizationDim)); 241 } 242 operator =armnn::TensorInfo::Quantization243 Quantization& operator=(const Quantization& other) 244 { 245 if(this != &other) 246 { 247 m_Scales = other.m_Scales; 248 m_Offset = other.m_Offset; 249 m_QuantizationDim = other.m_QuantizationDim; 250 } 251 return *this; 252 } 253 254 std::vector<float> m_Scales; 255 Optional<int32_t> m_Offset; 256 Optional<unsigned int> m_QuantizationDim; 257 258 } m_Quantization; 259 }; 260 261 using BindingPointInfo = std::pair<armnn::LayerBindingId, armnn::TensorInfo>; 262 263 template<typename MemoryType> 264 class BaseTensor 265 { 266 public: 267 /// Empty (invalid) constructor. 268 BaseTensor(); 269 270 /// Constructor from a raw memory pointer. 271 /// @param memoryArea - Region of CPU-addressable memory where tensor data will be stored. Must be valid while 272 /// workloads are on the fly. Tensor instances do not claim ownership of referenced memory regions, that is, 273 /// no attempt will be made by ArmNN to free these memory regions automatically. 274 BaseTensor(const TensorInfo& info, MemoryType memoryArea); 275 276 /// Tensors are copyable. 277 BaseTensor(const BaseTensor& other); 278 279 /// Tensors are copyable. 280 BaseTensor& operator=(const BaseTensor&); 281 GetInfo() const282 const TensorInfo& GetInfo() const { return m_Info; } GetInfo()283 TensorInfo& GetInfo() { return m_Info; } GetShape() const284 const TensorShape& GetShape() const { return m_Info.GetShape(); } GetShape()285 TensorShape& GetShape() { return m_Info.GetShape(); } 286 GetDataType() const287 DataType GetDataType() const { return m_Info.GetDataType(); } GetNumDimensions() const288 unsigned int GetNumDimensions() const { return m_Info.GetNumDimensions(); } GetNumBytes() const289 unsigned int GetNumBytes() const { return m_Info.GetNumBytes(); } GetNumElements() const290 unsigned int GetNumElements() const { return m_Info.GetNumElements(); } 291 GetMemoryArea() const292 MemoryType GetMemoryArea() const { return m_MemoryArea; } 293 294 protected: 295 /// Protected destructor to stop users from making these 296 /// (could still new one on the heap and then leak it...) ~BaseTensor()297 ~BaseTensor() {} 298 299 MemoryType m_MemoryArea; 300 301 private: 302 TensorInfo m_Info; 303 }; 304 305 /// A tensor defined by a TensorInfo (shape and data type) and a mutable backing store. 306 class Tensor : public BaseTensor<void*> 307 { 308 public: 309 /// Brings in the constructors and assignment operator. 310 using BaseTensor<void*>::BaseTensor; 311 }; 312 313 /// A tensor defined by a TensorInfo (shape and data type) and an immutable backing store. 314 class ConstTensor : public BaseTensor<const void*> 315 { 316 public: 317 /// Brings in the constructors and assignment operator. 318 using BaseTensor<const void*>::BaseTensor; ConstTensor()319 ConstTensor() : BaseTensor<const void*>() {} // This needs to be redefined explicitly?? 320 321 /// Can be implicitly constructed from non-const Tensor. ConstTensor(const Tensor & other)322 ConstTensor(const Tensor& other) : BaseTensor<const void*>(other.GetInfo(), other.GetMemoryArea()) {} 323 324 /// Constructor from a backing container. 325 /// @param container - An stl-like container type which implements data() and size() methods. 326 /// Presence of data() and size() is a strong indicator of the continuous memory layout of the container, 327 /// which is a requirement for Tensor data. Tensor instances do not claim ownership of referenced memory regions, 328 /// that is, no attempt will be made by ArmNN to free these memory regions automatically. 329 template < template<typename, typename...> class ContainerType, typename T, typename...ContainerArgs > ConstTensor(const TensorInfo & info,const ContainerType<T,ContainerArgs...> & container)330 ConstTensor(const TensorInfo& info, const ContainerType<T, ContainerArgs...>& container) 331 : BaseTensor<const void*>(info, container.data()) 332 { 333 if (container.size() * sizeof(T) != info.GetNumBytes()) 334 { 335 throw InvalidArgumentException("Container size is not correct"); 336 } 337 } 338 }; 339 340 using InputTensors = std::vector<std::pair<LayerBindingId, class ConstTensor>>; 341 using OutputTensors = std::vector<std::pair<LayerBindingId, class Tensor>>; 342 343 } // namespace armnn 344