1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
6 * @brief A header file that provides class for describing precision of data
7 * @file ie_precision.hpp
10 #include <unordered_map>
12 #include "details/ie_exception.hpp"
14 namespace InferenceEngine {
17 * @brief This class holds precision value and provides precision related operations
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 */
39 struct PrecisionInfo {
40 /** @brief Size of underlined element */
43 /** @brief Null terminated string with precision name */
44 const char *name = "UNSPECIFIED";
47 ePrecision value = Precision::UNSPECIFIED;
49 PrecisionInfo precisionInfo;
52 /** @brief Default constructor */
53 Precision() = default;
55 /** @brief Constructor with specified precision */
56 Precision(const Precision::ePrecision value) { // NOLINT
57 precisionInfo = getPrecisionInfo(value);
61 * @brief Custom precision constructor
63 * @param bitsSize size of elements
64 * @param name optional name string, used in serialisation
66 explicit Precision(size_t bitsSize, const char * name = nullptr) {
68 THROW_IE_EXCEPTION << "Precision with 0 elements size not supported";
70 precisionInfo.bitsSize = bitsSize;
71 if (name == nullptr) {
72 precisionInfo.name = "CUSTOM";
74 precisionInfo.name = name;
76 precisionInfo.value = CUSTOM;
79 /** @brief Creates custom precision with specific underlined type */
81 static Precision fromType(const char * typeName = nullptr) {
82 return Precision(8 * sizeof(T), typeName == nullptr ? typeid(T).name() : typeName);
85 /** @brief checks whether given storage class T can be used to store objects of current precision */
87 bool hasStorageType(const char * typeName = nullptr) const noexcept {
89 if (precisionInfo.value != BIN) {
90 if (sizeof(T) != size()) {
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>()
97 switch (precisionInfo.value) {
99 CASE2(FP16, int16_t, uint16_t);
106 CASE2(Q78, int16_t, uint16_t);
107 CASE2(BIN, int8_t, uint8_t);
109 return areSameStrings(name(), typeName == nullptr ? typeid(T).name() : typeName);
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);
125 /** @brief Equality operator with ePrecision enum value */
126 bool operator == (const ePrecision p) const noexcept {
127 return precisionInfo.value == p;
130 /** @brief Inequality operator with ePrecision enum value */
131 bool operator != (const ePrecision p) const noexcept {
132 return precisionInfo.value != p;
135 /** @brief Assignment operator with ePrecision enum value */
136 Precision & operator = (const ePrecision p) noexcept {
137 precisionInfo = getPrecisionInfo(p);
141 /** @brief Cast operator to a bool */
142 explicit operator bool() const noexcept {
143 return precisionInfo.value != UNSPECIFIED;
146 /** @brief Logical negation operator */
147 bool operator !() const noexcept {
148 return precisionInfo.value == UNSPECIFIED;
151 /** @brief Cast operator to a ePrecision */
152 operator Precision::ePrecision () const noexcept {
153 return precisionInfo.value;
156 /** @brief Getter of precision name */
157 const char *name() const noexcept {
158 return precisionInfo.name;
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}
172 PRECISION_NAME(FP32),
173 PRECISION_NAME(FP16),
174 PRECISION_NAME(MIXED),
176 #undef PRECISION_NAME
178 auto i = names.find(str);
179 return i == names.end() ? Precision() : Precision(i->second);
183 * @brief Returns size of single element of that precision in bits
185 * @returns Number of bits per element
187 size_t size() const {
188 if (precisionInfo.bitsSize == 0) {
189 THROW_IE_EXCEPTION << " cannot estimate element if precision is " << precisionInfo.name;
191 return precisionInfo.bitsSize >> 3;
194 /** @brief Checks if it is a floating point */
195 bool is_float() const noexcept {
196 return precisionInfo.isFloat;
201 * @brief Returns PrecisionInfo by its name
203 * @param name Name of precision
205 template<Precision::ePrecision precision>
206 static PrecisionInfo makePrecisionInfo(const char * name);
209 * @brief Compare two c-strings
211 * @param l Const pointer to first string
212 * @param r Const pointer to another string
213 * @returns True if strings are the same
215 static bool areSameStrings(const char *l, const char *r) noexcept {
219 if (l == nullptr || r == nullptr)
222 for (; *l && *r; l++, r++) {
223 if (*l != *r) return false;
229 * @brief Return PrecisionInfo
231 static PrecisionInfo getPrecisionInfo(ePrecision v) {
232 #define CASE(x) case x: return makePrecisionInfo<x>(#x);
245 default : return makePrecisionInfo<UNSPECIFIED>("UNSPECIFIED");
252 * @brief Particular precision traits
254 template<Precision::ePrecision p>
255 struct PrecisionTrait {
258 /** @cond INTERNAL */
260 struct PrecisionTrait<Precision::FP32> {
261 using value_type = float;
265 struct PrecisionTrait<Precision::FP16> {
266 using value_type = int16_t;
269 struct PrecisionTrait<Precision::Q78> {
270 using value_type = uint16_t;
273 struct PrecisionTrait<Precision::I16> {
274 using value_type = int16_t;
277 struct PrecisionTrait<Precision::U16> {
278 using value_type = uint16_t;
281 struct PrecisionTrait<Precision::U8> {
282 using value_type = uint8_t;
285 struct PrecisionTrait<Precision::I8> {
286 using value_type = int8_t;
289 struct PrecisionTrait<Precision::I32> {
290 using value_type = int32_t;
293 struct PrecisionTrait<Precision::I64> {
294 using value_type = int64_t;
297 struct PrecisionTrait<Precision::BIN> {
298 using value_type = int8_t;
302 inline uint8_t type_size_or_zero() {
307 struct PrecisionTrait<Precision::UNSPECIFIED> {
308 using value_type = void;
312 struct PrecisionTrait<Precision::MIXED> : PrecisionTrait<Precision::UNSPECIFIED>{
316 inline uint8_t type_size_or_zero<void>() {
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() {
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;
334 template<Precision::ePrecision precision>
335 inline Precision::PrecisionInfo Precision::makePrecisionInfo(const char *name) {
336 Precision::PrecisionInfo info;
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;
346 inline std::ostream & operator << (std::ostream &out, const InferenceEngine::Precision & p) {
347 return out << p.name();
350 inline std::ostream & operator << (std::ostream &out, const InferenceEngine::Precision::ePrecision & p) {
351 return out << Precision(p).name();
354 inline constexpr uint32_t getPrecisionMask(InferenceEngine::Precision::ePrecision precision1,
355 InferenceEngine::Precision::ePrecision precision2,
356 InferenceEngine::Precision::ePrecision precision3 = InferenceEngine::Precision::MIXED,
357 InferenceEngine::Precision::ePrecision precision4 = InferenceEngine::Precision::MIXED) {
358 return (precision1) | (precision2 << 8) | (precision3 << 16) | (precision4 << 24);
363 } // namespace InferenceEngine