ie_precision.hpp
Go to the documentation of this file.
1 // Copyright (C) 2018-2020 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4 
5 /**
6  * @brief A header file that provides class for describing precision of data
7  *
8  * @file ie_precision.hpp
9  */
10 #pragma once
11 
12 #include <string>
13 #include <unordered_map>
14 #include <vector>
15 
16 #include "details/ie_exception.hpp"
17 
18 namespace InferenceEngine {
19 
20 /**
21  * @brief This class holds precision value and provides precision related operations
22  */
23 class Precision {
24 public:
25  /** Enum to specify of different */
26  enum ePrecision : uint8_t {
27  UNSPECIFIED = 255, /**< Unspecified value. Used by default */
28  MIXED = 0, /**< Mixed value. Can be received from network. No applicable for tensors */
29  FP32 = 10, /**< 32bit floating point value */
30  FP16 = 11, /**< 16bit floating point value, 5 bit for exponent, 10 bit for mantisa */
31  BF16 = 12, /**< 16bit floating point value, 8 bit for exponent, 7 bit for mantisa*/
32  Q78 = 20, /**< 16bit specific signed fixed point precision */
33  I16 = 30, /**< 16bit signed integer value */
34  U8 = 40, /**< 8bit unsigned integer value */
35  I8 = 50, /**< 8bit signed integer value */
36  U16 = 60, /**< 16bit unsigned integer value */
37  I32 = 70, /**< 32bit signed integer value */
38  U32 = 74, /**< 32bit unsigned integer value */
39  I64 = 72, /**< 64bit signed integer value */
40  U64 = 73, /**< 64bit unsigned integer value */
41  BIN = 71, /**< 1bit integer value */
42  BOOL = 41, /**< 8bit bool type */
43  CUSTOM = 80 /**< custom precision has it's own name and size of elements */
44  };
45 
46 private:
47  struct PrecisionInfo {
48  /** @brief Size of underlined element */
49  size_t bitsSize = 0;
50 
51  /** @brief Null terminated string with precision name */
52  const char* name = "UNSPECIFIED";
53 
54  bool isFloat = false;
56  };
57  PrecisionInfo precisionInfo;
58 
59 public:
60  /** @brief Default constructor */
61  Precision() = default;
62 
63  /**
64  * @brief Constructor with specified precision
65  * @param value A value of ePrecision to create an object from
66  */
67  Precision(const Precision::ePrecision value) { // NOLINT
68  precisionInfo = getPrecisionInfo(value);
69  }
70 
71  /**
72  * @brief Custom precision constructor
73  *
74  * @param bitsSize size of elements
75  * @param name optional: name string, used in serialisation
76  */
77  explicit Precision(size_t bitsSize, const char* name = nullptr) {
78  if (bitsSize == 0) {
79  THROW_IE_EXCEPTION << "Precision with 0 elements size not supported";
80  }
81  precisionInfo.bitsSize = bitsSize;
82  if (name == nullptr) {
83  precisionInfo.name = "CUSTOM";
84  } else {
85  precisionInfo.name = name;
86  }
87  precisionInfo.value = CUSTOM;
88  }
89 
90  /** @brief Creates custom precision with specific underlined type */
91  template <class T>
92  static Precision fromType(const char* typeName = nullptr) {
93  return Precision(8 * sizeof(T), typeName == nullptr ? typeid(T).name() : typeName);
94  }
95 
96  /** @brief checks whether given storage class T can be used to store objects of current precision */
97  template <class T>
98  bool hasStorageType(const char* typeName = nullptr) const noexcept {
99  try {
100  if (precisionInfo.value != BIN) {
101  if (sizeof(T) != size()) {
102  return false;
103  }
104  }
105 #define CASE(x, y) \
106  case x: \
107  return std::is_same<T, y>()
108 #define CASE2(x, y1, y2) \
109  case x: \
110  return std::is_same<T, y1>() || std::is_same<T, y2>()
111 
112  switch (precisionInfo.value) {
113  CASE(FP32, float);
114  CASE2(FP16, int16_t, uint16_t);
115  CASE2(BF16, int16_t, uint16_t);
116  CASE(I8, int8_t);
117  CASE(I16, int16_t);
118  CASE(I32, int32_t);
119  CASE(I64, int64_t);
120  CASE(U8, uint8_t);
121  CASE(U16, uint16_t);
122  CASE(U32, uint32_t);
123  CASE(U64, uint64_t);
124  CASE(BOOL, uint8_t);
125  CASE2(Q78, int16_t, uint16_t);
126  CASE2(BIN, int8_t, uint8_t);
127  default:
128  return areSameStrings(name(), typeName == nullptr ? typeid(T).name() : typeName);
129 #undef CASE
130 #undef CASE2
131  }
132  } catch (...) {
133  return false;
134  }
135  }
136 
137  /**
138  * @brief Equality operator with Precision object
139  * @param p A value of Precision to compare with
140  * @return `true` if values represent the same precisions, `false` otherwise
141  */
142  bool operator==(const Precision& p) const noexcept {
143  return precisionInfo.value == p && precisionInfo.bitsSize == p.precisionInfo.bitsSize &&
144  areSameStrings(precisionInfo.name, p.precisionInfo.name);
145  }
146 
147  /**
148  * @brief Equality operator with ePrecision enum value
149  * @param p A value of ePrecision to compare with
150  * @return `true` if values represent the same precisions, `false` otherwise
151  */
152  bool operator==(const ePrecision p) const noexcept {
153  return precisionInfo.value == p;
154  }
155 
156  /**
157  * @brief Inequality operator with ePrecision enum value
158  * @param p A value of ePrecision to compare with
159  * @return `true` if values represent different precisions, `false` otherwise
160  */
161  bool operator!=(const ePrecision p) const noexcept {
162  return precisionInfo.value != p;
163  }
164 
165  /**
166  * @brief Assignment operator with ePrecision enum value
167  * @param p A value of ePrecision enumeration
168  * @return A Precision instance
169  */
170  Precision& operator=(const ePrecision p) noexcept {
171  precisionInfo = getPrecisionInfo(p);
172  return *this;
173  }
174 
175  /**
176  * @brief Cast operator to a bool
177  * @return `true` if precision is specified, `false` otherwise
178  */
179  explicit operator bool() const noexcept {
180  return precisionInfo.value != UNSPECIFIED;
181  }
182 
183  /**
184  * @brief Logical negation operator
185  * @return `true` if precision is NOT specified, `false` otherwise
186  */
187  bool operator!() const noexcept {
188  return precisionInfo.value == UNSPECIFIED;
189  }
190 
191  /**
192  * @brief Cast operator to a ePrecision
193  * @return A casted value of Precision::ePrecision enumeration
194  */
195  operator Precision::ePrecision() const noexcept {
196  return precisionInfo.value;
197  }
198 
199  /**
200  * @brief Gets the precision value of type ePrecision.
201  * @return The preccision value.
202  */
203  constexpr uint8_t getPrecVal() const noexcept {
204  return precisionInfo.value;
205  }
206 
207  /**
208  * @brief Getter of precision name
209  * @return A string representing precision name
210  */
211  const char* name() const noexcept {
212  return precisionInfo.name;
213  }
214 
215  /**
216  * @brief Creates Precision from string with precision name
217  * @param str A string representing precision
218  * @return Precision created from string representation
219  */
220  static Precision FromStr(const std::string& str) {
221  static std::unordered_map<std::string, ePrecision> names = {
222 #define PRECISION_NAME(s) {#s, s}
223  PRECISION_NAME(Q78), PRECISION_NAME(BOOL), PRECISION_NAME(BF16),
224  PRECISION_NAME(I8), PRECISION_NAME(I16), PRECISION_NAME(I32), PRECISION_NAME(I64),
225  PRECISION_NAME(U8), PRECISION_NAME(U16), PRECISION_NAME(U32), PRECISION_NAME(U64),
226  PRECISION_NAME(FP32), PRECISION_NAME(FP16), PRECISION_NAME(MIXED), PRECISION_NAME(BIN),
227 #undef PRECISION_NAME
228  };
229  auto i = names.find(str);
230  return i == names.end() ? Precision() : Precision(i->second);
231  }
232 
233  /**
234  * @brief Returns size of single element of that precision in bits
235  * @returns Number of bytes per element
236  */
237  size_t size() const {
238  if (precisionInfo.bitsSize == 0) {
239  THROW_IE_EXCEPTION << " cannot estimate element if precision is " << precisionInfo.name;
240  }
241  return precisionInfo.bitsSize >> 3;
242  }
243 
244  /**
245  * @brief Checks if it is a floating point value
246  * @return True if precision is float point, `false` otherwise
247  */
248  bool is_float() const noexcept {
249  return precisionInfo.isFloat;
250  }
251 
252  /**
253  * @brief Checks if it is a signed value
254  * @return True if precision is signed, `false` otherwise
255  */
256  bool isSigned() const noexcept {
257  return (precisionInfo.value == Precision::UNSPECIFIED) || (precisionInfo.value == Precision::MIXED) ||
258  (precisionInfo.value == Precision::FP32) || (precisionInfo.value == Precision::FP16) ||
259  (precisionInfo.value == Precision::Q78) || (precisionInfo.value == Precision::I16) ||
260  (precisionInfo.value == Precision::I8) || (precisionInfo.value == Precision::I32) ||
261  (precisionInfo.value == Precision::I64) || (precisionInfo.value == Precision::BIN) ||
262  (precisionInfo.value == Precision::BF16) || (precisionInfo.value == Precision::CUSTOM);
263  }
264 
265 protected:
266  /**
267  * @brief Creates PrecisionInfo by @p precision with a specified name
268  * @tparam precision A precision to create PrecisionInfo for
269  * @param name Name of precision
270  * @return A PrecisionInfo object
271  */
272  template <Precision::ePrecision precision>
273  static PrecisionInfo makePrecisionInfo(const char* name);
274 
275  /**
276  * @brief Compare two c-strings
277  *
278  * @param l Const pointer to first string
279  * @param r Const pointer to another string
280  * @returns True if strings are the same
281  */
282  static bool areSameStrings(const char* l, const char* r) noexcept {
283  if (l == r) return true;
284 
285  if (l == nullptr || r == nullptr) return false;
286 
287  for (; *l && *r; l++, r++) {
288  if (*l != *r) return false;
289  }
290  return *l == *r;
291  }
292 
293  /**
294  * @brief Creates PrecisionInfo based on ePrecision
295  * @param v A value of ePrecision emuneration
296  * @return Precision info object
297  */
298  static PrecisionInfo getPrecisionInfo(ePrecision v) {
299 #define CASE(x) \
300  case x: \
301  return makePrecisionInfo<x>(#x);
302  switch (v) {
303  CASE(FP32);
304  CASE(FP16);
305  CASE(BF16);
306  CASE(I8);
307  CASE(I16);
308  CASE(I32);
309  CASE(I64);
310  CASE(U8);
311  CASE(U16);
312  CASE(U32);
313  CASE(U64);
314  CASE(Q78);
315  CASE(MIXED);
316  CASE(BIN);
317  CASE(BOOL);
318  default:
319  return makePrecisionInfo<UNSPECIFIED>("UNSPECIFIED");
320 #undef CASE
321  }
322  }
323 };
324 
325 /**
326  * @brief Particular precision traits
327  */
328 template <Precision::ePrecision p>
329 struct PrecisionTrait {};
330 
331 /** @cond INTERNAL */
332 template <>
333 struct PrecisionTrait<Precision::FP32> {
334  using value_type = float;
335 };
336 
337 template <>
338 struct PrecisionTrait<Precision::FP16> {
339  using value_type = int16_t;
340 };
341 template <>
342 struct PrecisionTrait<Precision::BF16> {
343  using value_type = int16_t;
344 };
345 template<>
346 struct PrecisionTrait<Precision::Q78> {
347  using value_type = uint16_t;
348 };
349 template <>
350 struct PrecisionTrait<Precision::I16> {
351  using value_type = int16_t;
352 };
353 template <>
354 struct PrecisionTrait<Precision::U16> {
355  using value_type = uint16_t;
356 };
357 template <>
358 struct PrecisionTrait<Precision::U8> {
359  using value_type = uint8_t;
360 };
361 template <>
362 struct PrecisionTrait<Precision::I8> {
363  using value_type = int8_t;
364 };
365 template <>
366 struct PrecisionTrait<Precision::BOOL> {
367  using value_type = uint8_t;
368 };
369 template <>
370 struct PrecisionTrait<Precision::I32> {
371  using value_type = int32_t;
372 };
373 template <>
374 struct PrecisionTrait<Precision::U32> {
375  using value_type = uint32_t;
376 };
377 template <>
378 struct PrecisionTrait<Precision::I64> {
379  using value_type = int64_t;
380 };
381 template <>
382 struct PrecisionTrait<Precision::U64> {
383  using value_type = uint64_t;
384 };
385 template <>
386 struct PrecisionTrait<Precision::BIN> {
387  using value_type = int8_t;
388 };
389 
390 template <class T>
391 inline uint8_t type_size_or_zero() {
392  return sizeof(T);
393 }
394 
395 template <>
396 struct PrecisionTrait<Precision::UNSPECIFIED> {
397  using value_type = void;
398 };
399 
400 template <>
401 struct PrecisionTrait<Precision::MIXED> : PrecisionTrait<Precision::UNSPECIFIED> {};
402 
403 template <>
404 inline uint8_t type_size_or_zero<void>() {
405  return 0;
406 }
407 
408 template <Precision::ePrecision T>
409 inline typename std::enable_if<std::is_same<std::integral_constant<Precision::ePrecision, Precision::FP16>,
410  std::integral_constant<Precision::ePrecision, T>>::value,
411  bool>::type
412 is_floating() {
413  return true;
414 }
415 
416 template <Precision::ePrecision T>
417 inline typename std::enable_if<!std::is_same<std::integral_constant<Precision::ePrecision, Precision::FP16>,
418  std::integral_constant<Precision::ePrecision, T>>::value,
419  bool>::type
420 is_floating() {
421  return std::is_floating_point<typename PrecisionTrait<T>::value_type>::value;
422 }
423 
424 template <Precision::ePrecision precision>
425 inline Precision::PrecisionInfo Precision::makePrecisionInfo(const char* name) {
426  Precision::PrecisionInfo info;
427  info.name = name;
428 
429  size_t nBits = precision == BIN ? 1 : 8;
430  info.bitsSize = nBits * type_size_or_zero<typename PrecisionTrait<precision>::value_type>();
431  info.isFloat = is_floating<precision>();
432  info.value = precision;
433  return info;
434 }
435 
436 inline std::ostream& operator<<(std::ostream& out, const InferenceEngine::Precision& p) {
437  return out << p.name();
438 }
439 
440 inline std::ostream& operator<<(std::ostream& out, const InferenceEngine::Precision::ePrecision& p) {
441  return out << Precision(p).name();
442 }
443 
444 inline std::ostream& operator<<(std::ostream& os, const std::vector<Precision>& values) {
445  os << "{ ";
446  for (size_t i = 0; i < values.size(); ++i) {
447  os << values[i];
448  if (i != (values.size() - 1ul)) {
449  os << ", ";
450  }
451  }
452  os << " }";
453  return os;
454 }
455 
456 inline constexpr uint32_t getPrecisionMask(
460  return (precision1) | (precision2 << 8) | (precision3 << 16) | (precision4 << 24);
461 }
462 
463 /** @endcond */
464 
465 } // namespace InferenceEngine
This class holds precision value and provides precision related operations.
Definition: ie_precision.hpp:23
size_t size() const
Returns size of single element of that precision in bits.
Definition: ie_precision.hpp:237
bool operator==(const ePrecision p) const noexcept
Equality operator with ePrecision enum value.
Definition: ie_precision.hpp:152
static Precision FromStr(const std::string &str)
Creates Precision from string with precision name.
Definition: ie_precision.hpp:220
bool hasStorageType(const char *typeName=nullptr) const noexcept
checks whether given storage class T can be used to store objects of current precision
Definition: ie_precision.hpp:98
static PrecisionInfo makePrecisionInfo(const char *name)
Creates PrecisionInfo by precision with a specified name.
Precision()=default
Default constructor.
bool is_float() const noexcept
Checks if it is a floating point value.
Definition: ie_precision.hpp:248
bool operator!() const noexcept
Logical negation operator.
Definition: ie_precision.hpp:187
static Precision fromType(const char *typeName=nullptr)
Creates custom precision with specific underlined type.
Definition: ie_precision.hpp:92
static bool areSameStrings(const char *l, const char *r) noexcept
Compare two c-strings.
Definition: ie_precision.hpp:282
constexpr uint8_t getPrecVal() const noexcept
Gets the precision value of type ePrecision.
Definition: ie_precision.hpp:203
bool operator!=(const ePrecision p) const noexcept
Inequality operator with ePrecision enum value.
Definition: ie_precision.hpp:161
Precision(size_t bitsSize, const char *name=nullptr)
Custom precision constructor.
Definition: ie_precision.hpp:77
Precision & operator=(const ePrecision p) noexcept
Assignment operator with ePrecision enum value.
Definition: ie_precision.hpp:170
static PrecisionInfo getPrecisionInfo(ePrecision v)
Creates PrecisionInfo based on ePrecision.
Definition: ie_precision.hpp:298
const char * name() const noexcept
Getter of precision name.
Definition: ie_precision.hpp:211
ePrecision
Definition: ie_precision.hpp:26
@ BIN
Definition: ie_precision.hpp:41
@ U8
Definition: ie_precision.hpp:34
@ FP16
Definition: ie_precision.hpp:30
@ I32
Definition: ie_precision.hpp:37
@ FP32
Definition: ie_precision.hpp:29
@ U64
Definition: ie_precision.hpp:40
@ U32
Definition: ie_precision.hpp:38
@ I64
Definition: ie_precision.hpp:39
@ I8
Definition: ie_precision.hpp:35
@ CUSTOM
Definition: ie_precision.hpp:43
@ MIXED
Definition: ie_precision.hpp:28
@ Q78
Definition: ie_precision.hpp:32
@ I16
Definition: ie_precision.hpp:33
@ BF16
Definition: ie_precision.hpp:31
@ UNSPECIFIED
Definition: ie_precision.hpp:27
@ U16
Definition: ie_precision.hpp:36
@ BOOL
Definition: ie_precision.hpp:42
Precision(const Precision::ePrecision value)
Constructor with specified precision.
Definition: ie_precision.hpp:67
bool operator==(const Precision &p) const noexcept
Equality operator with Precision object.
Definition: ie_precision.hpp:142
bool isSigned() const noexcept
Checks if it is a signed value.
Definition: ie_precision.hpp:256
@ U64
Definition: ie_c_api.h:184
@ U8
Definition: ie_c_api.h:179
@ FP32
Definition: ie_c_api.h:175
@ BIN
Definition: ie_c_api.h:186
@ FP16
Definition: ie_c_api.h:176
@ MIXED
Definition: ie_c_api.h:174
@ U32
Definition: ie_c_api.h:185
@ I32
Definition: ie_c_api.h:182
@ Q78
Definition: ie_c_api.h:177
@ I8
Definition: ie_c_api.h:180
@ I16
Definition: ie_c_api.h:178
@ I64
Definition: ie_c_api.h:183
@ UNSPECIFIED
Definition: ie_c_api.h:173
@ U16
Definition: ie_c_api.h:181
std::ostream & operator<<(std::ostream &out, const Layout &p)
Prints a string representation of InferenceEngine::Layout to a stream.
Definition: ie_common.h:101
A header file for the main Inference Engine exception.
#define THROW_IE_EXCEPTION
A macro used to throw the exception with a notable description.
Definition: ie_exception.hpp:25
Particular precision traits.
Definition: ie_precision.hpp:329