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