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