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