telsoa01 | 4fcda01 | 2018-03-09 14:13:49 +0000 | [diff] [blame] | 1 | // |
| 2 | // Copyright © 2017 Arm Ltd. All rights reserved. |
David Beck | ecb56cd | 2018-09-05 12:52:57 +0100 | [diff] [blame] | 3 | // SPDX-License-Identifier: MIT |
telsoa01 | 4fcda01 | 2018-03-09 14:13:49 +0000 | [diff] [blame] | 4 | // |
Aron Virginas-Tar | c0a87c1 | 2019-10-29 17:58:36 +0000 | [diff] [blame] | 5 | |
telsoa01 | 4fcda01 | 2018-03-09 14:13:49 +0000 | [diff] [blame] | 6 | #include "armnn/Tensor.hpp" |
| 7 | #include "armnn/Utils.hpp" |
| 8 | #include "armnn/Exceptions.hpp" |
| 9 | #include "armnn/TypesUtils.hpp" |
| 10 | |
| 11 | #include <boost/assert.hpp> |
telsoa01 | 4fcda01 | 2018-03-09 14:13:49 +0000 | [diff] [blame] | 12 | #include <boost/numeric/conversion/cast.hpp> |
| 13 | |
Aron Virginas-Tar | 06e25c4 | 2019-02-21 15:45:03 +0000 | [diff] [blame] | 14 | #include <sstream> |
| 15 | |
telsoa01 | 4fcda01 | 2018-03-09 14:13:49 +0000 | [diff] [blame] | 16 | namespace armnn |
| 17 | { |
| 18 | |
| 19 | // --- |
| 20 | // --- TensorShape |
| 21 | // --- |
| 22 | |
| 23 | TensorShape::TensorShape() |
| 24 | : m_NumDimensions(0) |
| 25 | { |
| 26 | } |
| 27 | |
Matteo Martincigh | f9afc79 | 2018-12-06 12:03:17 +0000 | [diff] [blame] | 28 | TensorShape::TensorShape(unsigned int numDimensions) |
| 29 | : m_NumDimensions(numDimensions) |
| 30 | { |
| 31 | if (numDimensions < 1) |
| 32 | { |
| 33 | throw InvalidArgumentException("Tensor numDimensions must be greater than 0"); |
| 34 | } |
| 35 | |
| 36 | if (numDimensions > MaxNumOfTensorDimensions) |
| 37 | { |
| 38 | throw InvalidArgumentException("Tensor numDimensions must be less than or equal to MaxNumOfTensorDimensions"); |
| 39 | } |
| 40 | |
| 41 | std::fill(m_Dimensions.begin(), m_Dimensions.begin() + m_NumDimensions, 0); |
| 42 | } |
| 43 | |
telsoa01 | 4fcda01 | 2018-03-09 14:13:49 +0000 | [diff] [blame] | 44 | TensorShape::TensorShape(const unsigned int numDimensions, const unsigned int* const dimensionSizes) |
| 45 | : m_NumDimensions(numDimensions) |
| 46 | { |
| 47 | if (numDimensions < 1) |
| 48 | { |
| 49 | throw InvalidArgumentException("Tensor numDimensions must be greater than 0"); |
| 50 | } |
| 51 | |
| 52 | if (numDimensions > MaxNumOfTensorDimensions) |
| 53 | { |
| 54 | throw InvalidArgumentException("Tensor numDimensions must be less than or equal to MaxNumOfTensorDimensions"); |
| 55 | } |
| 56 | |
| 57 | if (dimensionSizes == nullptr) |
| 58 | { |
| 59 | throw InvalidArgumentException("Tensor dimensionSizes must not be NULL"); |
| 60 | } |
| 61 | |
| 62 | std::copy(dimensionSizes, dimensionSizes + numDimensions, m_Dimensions.begin()); |
| 63 | } |
| 64 | |
| 65 | TensorShape::TensorShape(std::initializer_list<unsigned int> dimensionSizeList) |
| 66 | : TensorShape(boost::numeric_cast<unsigned int>(dimensionSizeList.size()), dimensionSizeList.begin()) |
| 67 | { |
| 68 | } |
| 69 | |
| 70 | TensorShape::TensorShape(const TensorShape& other) |
| 71 | : m_NumDimensions(other.m_NumDimensions) |
| 72 | { |
| 73 | std::copy(other.m_Dimensions.cbegin(), other.m_Dimensions.cbegin() + other.m_NumDimensions, m_Dimensions.begin()); |
| 74 | } |
| 75 | |
| 76 | TensorShape& TensorShape::operator =(const TensorShape& other) |
| 77 | { |
| 78 | m_NumDimensions = other.m_NumDimensions; |
| 79 | std::copy(other.m_Dimensions.cbegin(), other.m_Dimensions.cbegin() + other.m_NumDimensions, m_Dimensions.begin()); |
| 80 | return *this; |
| 81 | } |
| 82 | |
Aron Virginas-Tar | 06e25c4 | 2019-02-21 15:45:03 +0000 | [diff] [blame] | 83 | unsigned int TensorShape::operator[](unsigned int i) const |
| 84 | { |
| 85 | CheckDimensionIndex(i); |
| 86 | return m_Dimensions.at(i); |
| 87 | } |
| 88 | |
| 89 | unsigned int& TensorShape::operator[](unsigned int i) |
| 90 | { |
| 91 | CheckDimensionIndex(i); |
| 92 | return m_Dimensions.at(i); |
| 93 | } |
| 94 | |
telsoa01 | 4fcda01 | 2018-03-09 14:13:49 +0000 | [diff] [blame] | 95 | bool TensorShape::operator==(const TensorShape& other) const |
| 96 | { |
| 97 | return ((m_NumDimensions == other.m_NumDimensions) && |
| 98 | std::equal(m_Dimensions.cbegin(), m_Dimensions.cbegin() + m_NumDimensions, other.m_Dimensions.cbegin())); |
| 99 | } |
| 100 | |
| 101 | bool TensorShape::operator!=(const TensorShape& other) const |
| 102 | { |
| 103 | return !(*this == other); |
| 104 | } |
| 105 | |
| 106 | unsigned int TensorShape::GetNumElements() const |
| 107 | { |
| 108 | if (m_NumDimensions == 0) |
| 109 | { |
| 110 | return 0; |
| 111 | } |
| 112 | |
| 113 | unsigned int count = 1; |
| 114 | for (unsigned int i = 0; i < m_NumDimensions; i++) |
| 115 | { |
| 116 | count *= m_Dimensions[i]; |
| 117 | } |
| 118 | |
| 119 | return count; |
| 120 | } |
| 121 | |
Aron Virginas-Tar | 06e25c4 | 2019-02-21 15:45:03 +0000 | [diff] [blame] | 122 | void TensorShape::CheckDimensionIndex(unsigned int i) const |
| 123 | { |
| 124 | if (i >= m_NumDimensions) |
| 125 | { |
| 126 | std::stringstream errorMessage; |
| 127 | errorMessage << "Invalid dimension index: " << i << " (number of dimensions is " << m_NumDimensions << ")"; |
| 128 | throw InvalidArgumentException(errorMessage.str(), CHECK_LOCATION()); |
| 129 | } |
| 130 | } |
| 131 | |
telsoa01 | 4fcda01 | 2018-03-09 14:13:49 +0000 | [diff] [blame] | 132 | // --- |
| 133 | // --- TensorInfo |
| 134 | // --- |
| 135 | |
| 136 | TensorInfo::TensorInfo() |
| 137 | : m_DataType(DataType::Float32) |
| 138 | { |
| 139 | } |
| 140 | |
Aron Virginas-Tar | c0a87c1 | 2019-10-29 17:58:36 +0000 | [diff] [blame] | 141 | TensorInfo::TensorInfo(const TensorShape& shape, |
| 142 | DataType dataType, |
| 143 | float quantizationScale, |
| 144 | int32_t quantizationOffset) |
| 145 | : m_Shape(shape) |
| 146 | , m_DataType(dataType) |
telsoa01 | 4fcda01 | 2018-03-09 14:13:49 +0000 | [diff] [blame] | 147 | { |
Aron Virginas-Tar | c0a87c1 | 2019-10-29 17:58:36 +0000 | [diff] [blame] | 148 | SetQuantizationScale(quantizationScale); |
| 149 | SetQuantizationOffset(quantizationOffset); |
telsoa01 | 4fcda01 | 2018-03-09 14:13:49 +0000 | [diff] [blame] | 150 | } |
| 151 | |
Aron Virginas-Tar | c0a87c1 | 2019-10-29 17:58:36 +0000 | [diff] [blame] | 152 | TensorInfo::TensorInfo(unsigned int numDimensions, |
| 153 | const unsigned int* dimensionSizes, |
| 154 | DataType dataType, |
| 155 | float quantizationScale, |
| 156 | int32_t quantizationOffset) |
| 157 | : m_Shape(numDimensions, dimensionSizes) |
| 158 | , m_DataType(dataType) |
telsoa01 | 4fcda01 | 2018-03-09 14:13:49 +0000 | [diff] [blame] | 159 | { |
Aron Virginas-Tar | c0a87c1 | 2019-10-29 17:58:36 +0000 | [diff] [blame] | 160 | SetQuantizationScale(quantizationScale); |
| 161 | SetQuantizationOffset(quantizationOffset); |
| 162 | } |
| 163 | |
| 164 | TensorInfo::TensorInfo(const TensorShape& shape, |
| 165 | DataType dataType, |
| 166 | const std::vector<float>& quantizationScales, |
| 167 | unsigned int quantizationDim) |
| 168 | : m_Shape(shape) |
| 169 | , m_DataType(dataType) |
| 170 | { |
| 171 | SetQuantizationScales(quantizationScales); |
| 172 | SetQuantizationDim(MakeOptional<unsigned int>(quantizationDim)); |
| 173 | } |
| 174 | |
| 175 | TensorInfo::TensorInfo(unsigned int numDimensions, |
| 176 | const unsigned int* dimensionSizes, |
| 177 | DataType dataType, |
| 178 | const std::vector<float>& quantizationScales, |
| 179 | unsigned int quantizationDim) |
| 180 | : m_Shape(numDimensions, dimensionSizes) |
| 181 | , m_DataType(dataType) |
| 182 | { |
| 183 | SetQuantizationScales(quantizationScales); |
| 184 | SetQuantizationDim(MakeOptional<unsigned int>(quantizationDim)); |
telsoa01 | 4fcda01 | 2018-03-09 14:13:49 +0000 | [diff] [blame] | 185 | } |
| 186 | |
| 187 | TensorInfo::TensorInfo(const TensorInfo& other) |
| 188 | : m_Shape(other.m_Shape) |
| 189 | , m_DataType(other.m_DataType) |
| 190 | , m_Quantization(other.m_Quantization) |
Aron Virginas-Tar | c0a87c1 | 2019-10-29 17:58:36 +0000 | [diff] [blame] | 191 | {} |
telsoa01 | 4fcda01 | 2018-03-09 14:13:49 +0000 | [diff] [blame] | 192 | |
| 193 | TensorInfo& TensorInfo::operator=(const TensorInfo& other) |
| 194 | { |
| 195 | m_Shape = other.m_Shape; |
| 196 | m_DataType = other.m_DataType; |
| 197 | m_Quantization = other.m_Quantization; |
| 198 | return *this; |
| 199 | } |
| 200 | |
| 201 | bool TensorInfo::operator==(const TensorInfo& other) const |
| 202 | { |
| 203 | return ((m_Shape == other.m_Shape) && |
| 204 | (m_DataType == other.m_DataType) && |
| 205 | (m_Quantization == other.m_Quantization)); |
| 206 | } |
| 207 | |
| 208 | bool TensorInfo::operator!=(const TensorInfo& other) const |
| 209 | { |
| 210 | return !(*this == other); |
| 211 | } |
| 212 | |
| 213 | unsigned int TensorInfo::GetNumBytes() const |
| 214 | { |
| 215 | return GetDataTypeSize(m_DataType) * GetNumElements(); |
| 216 | } |
| 217 | |
Derek Lamberti | 0790dce | 2019-04-15 18:37:35 +0100 | [diff] [blame] | 218 | bool TensorInfo::IsTypeSpaceMatch(const TensorInfo& other) const |
| 219 | { |
| 220 | bool match = true; |
| 221 | |
| 222 | match &= m_DataType == other.m_DataType; |
| 223 | |
Aron Virginas-Tar | c0a87c1 | 2019-10-29 17:58:36 +0000 | [diff] [blame] | 224 | if (IsQuantized() && !HasMultipleQuantizationScales()) |
Derek Lamberti | 0790dce | 2019-04-15 18:37:35 +0100 | [diff] [blame] | 225 | { |
| 226 | match &= GetQuantizationScale() == other.GetQuantizationScale() && |
| 227 | GetQuantizationOffset() == other.GetQuantizationOffset(); |
| 228 | } |
| 229 | return match; |
| 230 | } |
| 231 | |
Aron Virginas-Tar | 5edc881 | 2019-11-05 18:00:21 +0000 | [diff] [blame] | 232 | bool TensorInfo::HasPerAxisQuantization() const |
| 233 | { |
| 234 | return HasMultipleQuantizationScales() || m_Quantization.m_QuantizationDim.has_value(); |
| 235 | } |
| 236 | |
Aron Virginas-Tar | c0a87c1 | 2019-10-29 17:58:36 +0000 | [diff] [blame] | 237 | std::vector<float> TensorInfo::GetQuantizationScales() const |
| 238 | { |
| 239 | return m_Quantization.m_Scales; |
| 240 | } |
| 241 | |
| 242 | void TensorInfo::SetQuantizationScales(const std::vector<float>& scales) |
| 243 | { |
| 244 | m_Quantization.m_Scales = scales; |
| 245 | } |
| 246 | |
| 247 | float TensorInfo::GetQuantizationScale() const |
| 248 | { |
| 249 | if (m_Quantization.m_Scales.empty()) |
| 250 | { |
| 251 | // NOTE: old default for backward compatibility |
| 252 | return 1.0f; |
| 253 | } |
| 254 | |
| 255 | BOOST_ASSERT(!HasMultipleQuantizationScales()); |
| 256 | return m_Quantization.m_Scales[0]; |
| 257 | } |
| 258 | |
| 259 | void TensorInfo::SetQuantizationScale(float scale) |
| 260 | { |
| 261 | m_Quantization.m_Scales = { scale }; |
| 262 | } |
| 263 | |
| 264 | int32_t TensorInfo::GetQuantizationOffset() const |
| 265 | { |
| 266 | if (!m_Quantization.m_Offset.has_value()) |
| 267 | { |
| 268 | // NOTE: old default for backward compatibility |
| 269 | return 0; |
| 270 | } |
| 271 | |
| 272 | return m_Quantization.m_Offset.value(); |
| 273 | } |
| 274 | |
| 275 | void TensorInfo::SetQuantizationOffset(int32_t offset) |
| 276 | { |
| 277 | m_Quantization.m_Offset = MakeOptional<int32_t>(offset); |
| 278 | } |
| 279 | |
| 280 | Optional<unsigned int> TensorInfo::GetQuantizationDim() const |
| 281 | { |
| 282 | return m_Quantization.m_QuantizationDim; |
| 283 | } |
| 284 | |
| 285 | void TensorInfo::SetQuantizationDim(const Optional<unsigned int>& quantizationDim) |
| 286 | { |
| 287 | m_Quantization.m_QuantizationDim = quantizationDim; |
| 288 | } |
| 289 | |
| 290 | bool TensorInfo::IsQuantized() const |
| 291 | { |
Derek Lamberti | d466a54 | 2020-01-22 15:37:29 +0000 | [diff] [blame] | 292 | return IsQuantizedType(m_DataType); |
Aron Virginas-Tar | c0a87c1 | 2019-10-29 17:58:36 +0000 | [diff] [blame] | 293 | } |
| 294 | |
telsoa01 | 4fcda01 | 2018-03-09 14:13:49 +0000 | [diff] [blame] | 295 | // --- |
| 296 | // --- BaseTensor |
| 297 | // --- |
| 298 | |
| 299 | template<typename MemoryType> |
| 300 | BaseTensor<MemoryType>::BaseTensor() |
| 301 | : m_MemoryArea(nullptr) |
| 302 | { |
| 303 | } |
| 304 | |
| 305 | template<typename MemoryType> |
| 306 | BaseTensor<MemoryType>::BaseTensor(const TensorInfo& info, MemoryType memoryArea) |
| 307 | : m_MemoryArea(memoryArea) |
| 308 | , m_Info(info) |
| 309 | { |
| 310 | } |
| 311 | |
| 312 | template<typename MemoryType> |
| 313 | BaseTensor<MemoryType>::BaseTensor(const BaseTensor<MemoryType>& other) |
| 314 | : m_MemoryArea(other.m_MemoryArea) |
| 315 | , m_Info(other.GetInfo()) |
| 316 | { |
| 317 | } |
| 318 | |
| 319 | template<typename MemoryType> |
| 320 | BaseTensor<MemoryType>& BaseTensor<MemoryType>::operator =(const BaseTensor<MemoryType>& other) |
| 321 | { |
| 322 | m_Info = other.m_Info; |
| 323 | m_MemoryArea = other.m_MemoryArea; |
| 324 | return *this; |
| 325 | } |
| 326 | |
telsoa01 | c577f2c | 2018-08-31 09:22:23 +0100 | [diff] [blame] | 327 | // Explicit instantiations. |
telsoa01 | 4fcda01 | 2018-03-09 14:13:49 +0000 | [diff] [blame] | 328 | template class BaseTensor<const void*>; |
| 329 | template class BaseTensor<void*>; |
| 330 | |
| 331 | } // namespace armnn |