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