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  BIN = 71, /**< 1bit integer value */
34  CUSTOM = 80 /**< custom precision has it's own name and size of elements */
35  };
36 
37 private:
38  struct PrecisionInfo {
39  /** @brief Size of underlined element */
40  size_t bitsSize = 0;
41 
42  /** @brief Null terminated string with precision name */
43  const char *name = "UNSPECIFIED";
44 
45  bool isFloat = false;
47  };
48  PrecisionInfo precisionInfo;
49 
50 public:
51  /** @brief Default constructor */
52  Precision() = default;
53 
54  /** @brief Constructor with specified precision */
55  Precision(const Precision::ePrecision value) { // NOLINT
56  precisionInfo = getPrecisionInfo(value);
57  }
58 
59  /**
60  * @brief Custom precision constructor
61  * @param byteSize size of elements
62  * @param name optional name string, used in serialisation
63  */
64  explicit Precision(size_t bitsSize, const char * name = nullptr) {
65  if (bitsSize == 0) {
66  THROW_IE_EXCEPTION << "Precision with 0 elements size not supported";
67  }
68  precisionInfo.bitsSize = bitsSize;
69  if (name == nullptr) {
70  precisionInfo.name = "CUSTOM";
71  } else {
72  precisionInfo.name = name;
73  }
74  precisionInfo.value = CUSTOM;
75  }
76 
77  /** @brief Creates custom precision with specific underlined type */
78  template <class T>
79  static Precision fromType(const char * typeName = nullptr) {
80  return Precision(8 * sizeof(T), typeName == nullptr ? typeid(T).name() : typeName);
81  }
82 
83  /** @brief checks whether given storage class T can be used to store objects of current precision */
84  template <class T>
85  bool hasStorageType(const char * typeName = nullptr) const noexcept {
86  if (precisionInfo.value != BIN) {
87  if (sizeof(T) != size()) {
88  return false;
89  }
90  }
91 #define CASE(x, y) case x: return std::is_same<T, y>()
92 #define CASE2(x, y1, y2) case x: return std::is_same<T, y1>() || std::is_same<T, y2>()
93 
94  switch (precisionInfo.value) {
95  CASE(FP32, float);
96  CASE2(FP16, int16_t, uint16_t);
97  CASE(I16, int16_t);
98  CASE(I32, int32_t);
99  CASE(U16, uint16_t);
100  CASE(U8, uint8_t);
101  CASE(I8, int8_t);
102  CASE2(Q78, int16_t, uint16_t);
103  CASE2(BIN, int8_t, uint8_t);
104  default : return areSameStrings(name(), typeName == nullptr ? typeid(T).name() : typeName);
105 #undef CASE
106 #undef CASE2
107  }
108  }
109 
110  /** @brief Equality operator with Precision object */
111  bool operator == (const Precision & p) const noexcept {
112  return precisionInfo.value == p &&
113  precisionInfo.bitsSize == p.precisionInfo.bitsSize &&
114  areSameStrings(precisionInfo.name, p.precisionInfo.name);
115  }
116 
117  /** @brief Equality operator with ePrecision enum value */
118  bool operator == (const ePrecision p) const noexcept {
119  return precisionInfo.value == p;
120  }
121 
122  /** @brief Inequality operator with ePrecision enum value */
123  bool operator != (const ePrecision p) const noexcept {
124  return precisionInfo.value != p;
125  }
126 
127  /** @brief Assignment operator with ePrecision enum value */
128  Precision & operator = (const ePrecision p) noexcept {
129  precisionInfo = getPrecisionInfo(p);
130  return *this;
131  }
132 
133  /** @brief Cast operator to a bool */
134  explicit operator bool() const noexcept {
135  return precisionInfo.value != UNSPECIFIED;
136  }
137 
138  /** @brief Logical negation operator */
139  bool operator !() const noexcept {
140  return precisionInfo.value == UNSPECIFIED;
141  }
142 
143  /** @brief Cast operator to a ePrecision */
144  operator Precision::ePrecision () const noexcept {
145  return precisionInfo.value;
146  }
147 
148  /** @brief Getter of precision name */
149  const char *name() const noexcept {
150  return precisionInfo.name;
151  }
152 
153  /** @brief Creates from string with precision name */
154  static Precision FromStr(const std::string &str) {
155  static std::unordered_map<std::string, ePrecision > names = {
156 #define PRECISION_NAME(s) {#s, s}
157  PRECISION_NAME(Q78),
158  PRECISION_NAME(U8),
159  PRECISION_NAME(I8),
160  PRECISION_NAME(I16),
161  PRECISION_NAME(I32),
162  PRECISION_NAME(U16),
163  PRECISION_NAME(FP32),
164  PRECISION_NAME(FP16),
165  PRECISION_NAME(MIXED),
166  PRECISION_NAME(BIN),
167 #undef PRECISION_NAME
168  };
169  auto i = names.find(str);
170  return i == names.end() ? Precision() : Precision(i->second);
171  }
172 
173  /**
174  * @brief Returns size in bytes of single element of that precision
175  * @deprecated : size of precision will be report in bits in future releases
176  */
177  size_t size() const {
178  if (precisionInfo.bitsSize == 0) {
179  THROW_IE_EXCEPTION << " cannot estimate element if precision is " << precisionInfo.name;
180  }
181  return precisionInfo.bitsSize >> 3;
182  }
183 
184  /** @brief Checks if it is a floating point */
185  bool is_float() const {
186  return precisionInfo.isFloat;
187  }
188 
189  protected:
190  template<Precision::ePrecision precision>
191  static PrecisionInfo makePrecisionInfo(const char * name);
192 
193  static bool areSameStrings(const char *l, const char *r) noexcept {
194  if (l == r)
195  return true;
196 
197  if (l == nullptr || r == nullptr)
198  return false;
199 
200  for (; *l && *r; l++, r++) {
201  if (*l != *r) return false;
202  }
203  return *l == *r;
204  }
205 
206  static PrecisionInfo getPrecisionInfo(ePrecision v) {
207 #define CASE(x) case x: return makePrecisionInfo<x>(#x);
208  switch (v) {
209  CASE(FP32);
210  CASE(FP16);
211  CASE(I16);
212  CASE(I32);
213  CASE(U16);
214  CASE(U8);
215  CASE(I8);
216  CASE(Q78);
217  CASE(MIXED);
218  CASE(BIN);
219  default : return makePrecisionInfo<UNSPECIFIED>("UNSPECIFIED");
220 #undef CASE
221  }
222  }
223 };
224 
225 /**
226  * @brief Particular precision traits
227  */
228 template<Precision::ePrecision p>
230 };
231 
232 /** @cond INTERNAL */
233 template<>
234 struct PrecisionTrait<Precision::FP32> {
235  using value_type = float;
236 };
237 
238 template<>
239 struct PrecisionTrait<Precision::FP16> {
240  using value_type = int16_t;
241 };
242 template<>
243 struct PrecisionTrait<Precision::Q78> {
244  using value_type = uint16_t;
245 };
246 template<>
247 struct PrecisionTrait<Precision::I16> {
248  using value_type = int16_t;
249 };
250 template<>
251 struct PrecisionTrait<Precision::U16> {
252  using value_type = uint16_t;
253 };
254 template<>
255 struct PrecisionTrait<Precision::U8> {
256  using value_type = uint8_t;
257 };
258 template<>
259 struct PrecisionTrait<Precision::I8> {
260  using value_type = int8_t;
261 };
262 template<>
263 struct PrecisionTrait<Precision::I32> {
264  using value_type = int32_t;
265 };
266 template<>
267 struct PrecisionTrait<Precision::BIN> {
268  using value_type = int8_t;
269 };
270 
271 template<class T>
272 inline uint8_t type_size_or_zero() {
273  return sizeof(T);
274 }
275 
276 template<>
277 struct PrecisionTrait<Precision::UNSPECIFIED> {
278  using value_type = void;
279 };
280 
281 template<>
282 struct PrecisionTrait<Precision::MIXED> : PrecisionTrait<Precision::UNSPECIFIED>{
283 };
284 
285 template<>
286 inline uint8_t type_size_or_zero<void>() {
287  return 0;
288 }
289 
290 template<Precision::ePrecision T>
291 inline typename std::enable_if<std::is_same<
292  std::integral_constant<Precision::ePrecision, Precision::FP16>,
293  std::integral_constant<Precision::ePrecision, T>>::value, bool>::type is_floating() {
294  return true;
295 }
296 
297 template<Precision::ePrecision T>
298 inline typename std::enable_if<!std::is_same<
299  std::integral_constant<Precision::ePrecision, Precision::FP16>,
300  std::integral_constant<Precision::ePrecision, T>>::value, bool>::type is_floating() {
301  return std::is_floating_point<typename PrecisionTrait<T>::value_type>::value;
302 }
303 
304 template<Precision::ePrecision precision>
305 inline Precision::PrecisionInfo Precision::makePrecisionInfo(const char *name) {
306  Precision::PrecisionInfo info;
307  info.name = name;
308 
309  int nBits = precision == BIN ? 1 : 8;
310  info.bitsSize = nBits * type_size_or_zero<typename PrecisionTrait<precision>::value_type>();
311  info.isFloat = is_floating<precision>();
312  info.value = precision;
313  return info;
314 }
315 
316 inline std::ostream & operator << (std::ostream &out, const InferenceEngine::Precision & p) {
317  return out << p.name();
318 }
319 
320 inline std::ostream & operator << (std::ostream &out, const InferenceEngine::Precision::ePrecision & p) {
321  return out << Precision(p).name();
322 }
323 
324 /** @endcond */
325 
326 } // 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:229
static Precision fromType(const char *typeName=nullptr)
Creates custom precision with specific underlined type.
Definition: ie_precision.hpp:79
Definition: ie_argmax_layer.hpp:11
Definition: ie_precision.hpp:30
bool operator!() const noexcept
Logical negation operator.
Definition: ie_precision.hpp:139
Precision & operator=(const ePrecision p) noexcept
Assignment operator with ePrecision enum value.
Definition: ie_precision.hpp:128
Definition: ie_precision.hpp:27
size_t size() const
Returns size in bytes of single element of that precision.
Definition: ie_precision.hpp:177
Definition: ie_precision.hpp:26
bool operator==(const Precision &p) const noexcept
Equality operator with Precision object.
Definition: ie_precision.hpp:111
Definition: ie_precision.hpp:33
Definition: ie_precision.hpp:34
static Precision FromStr(const std::string &str)
Creates from string with precision name.
Definition: ie_precision.hpp:154
Precision(size_t bitsSize, const char *name=nullptr)
Custom precision constructor.
Definition: ie_precision.hpp:64
Definition: ie_precision.hpp:29
Definition: ie_precision.hpp:24
Definition: ie_precision.hpp:32
bool is_float() const
Checks if it is a floating point.
Definition: ie_precision.hpp:185
Definition: ie_precision.hpp:28
Precision(const Precision::ePrecision value)
Constructor with specified precision.
Definition: ie_precision.hpp:55
bool operator!=(const ePrecision p) const noexcept
Inequality operator with ePrecision enum value.
Definition: ie_precision.hpp:123
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:85
const char * name() const noexcept
Getter of precision name.
Definition: ie_precision.hpp:149