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