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