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