1 // Copyright (C) 2018-2020 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
6 * @brief A header file that provides class for describing precision of data
8 * @file ie_precision.hpp
12 #include <unordered_map>
15 #include "details/ie_exception.hpp"
17 namespace InferenceEngine {
20 * @brief This class holds precision value and provides precision related operations
24 /** Enum to specify of different */
25 enum ePrecision : uint8_t {
26 UNSPECIFIED = 255, /**< Unspecified value. Used by default */
27 MIXED = 0, /**< Mixed value. Can be received from network. No applicable for tensors */
28 FP32 = 10, /**< 32bit floating point value */
29 FP16 = 11, /**< 16bit floating point value */
30 Q78 = 20, /**< 16bit specific signed fixed point precision */
31 I16 = 30, /**< 16bit signed integer value */
32 U8 = 40, /**< 8bit unsigned integer value */
33 I8 = 50, /**< 8bit signed integer value */
34 U16 = 60, /**< 16bit unsigned integer value */
35 I32 = 70, /**< 32bit signed integer value */
36 I64 = 72, /**< 64bit signed integer value */
37 BIN = 71, /**< 1bit integer value */
38 BOOL = 41, /**< 8bit bool type */
39 CUSTOM = 80 /**< custom precision has it's own name and size of elements */
43 struct PrecisionInfo {
44 /** @brief Size of underlined element */
47 /** @brief Null terminated string with precision name */
48 const char* name = "UNSPECIFIED";
51 ePrecision value = Precision::UNSPECIFIED;
53 PrecisionInfo precisionInfo;
56 /** @brief Default constructor */
57 Precision() = default;
59 /** @brief Constructor with specified precision */
60 Precision(const Precision::ePrecision value) { // NOLINT
61 precisionInfo = getPrecisionInfo(value);
65 * @brief Custom precision constructor
67 * @param bitsSize size of elements
68 * @param name optional name string, used in serialisation
70 explicit Precision(size_t bitsSize, const char* name = nullptr) {
72 THROW_IE_EXCEPTION << "Precision with 0 elements size not supported";
74 precisionInfo.bitsSize = bitsSize;
75 if (name == nullptr) {
76 precisionInfo.name = "CUSTOM";
78 precisionInfo.name = name;
80 precisionInfo.value = CUSTOM;
83 /** @brief Creates custom precision with specific underlined type */
85 static Precision fromType(const char* typeName = nullptr) {
86 return Precision(8 * sizeof(T), typeName == nullptr ? typeid(T).name() : typeName);
89 /** @brief checks whether given storage class T can be used to store objects of current precision */
91 bool hasStorageType(const char* typeName = nullptr) const noexcept {
93 if (precisionInfo.value != BIN) {
94 if (sizeof(T) != size()) {
100 return std::is_same<T, y>()
101 #define CASE2(x, y1, y2) \
103 return std::is_same<T, y1>() || std::is_same<T, y2>()
105 switch (precisionInfo.value) {
107 CASE2(FP16, int16_t, uint16_t);
115 CASE2(Q78, int16_t, uint16_t);
116 CASE2(BIN, int8_t, uint8_t);
118 return areSameStrings(name(), typeName == nullptr ? typeid(T).name() : typeName);
127 /** @brief Equality operator with Precision object */
128 bool operator==(const Precision& p) const noexcept {
129 return precisionInfo.value == p && precisionInfo.bitsSize == p.precisionInfo.bitsSize &&
130 areSameStrings(precisionInfo.name, p.precisionInfo.name);
133 /** @brief Equality operator with ePrecision enum value */
134 bool operator==(const ePrecision p) const noexcept {
135 return precisionInfo.value == p;
138 /** @brief Inequality operator with ePrecision enum value */
139 bool operator!=(const ePrecision p) const noexcept {
140 return precisionInfo.value != p;
143 /** @brief Assignment operator with ePrecision enum value */
144 Precision& operator=(const ePrecision p) noexcept {
145 precisionInfo = getPrecisionInfo(p);
149 /** @brief Cast operator to a bool */
150 explicit operator bool() const noexcept {
151 return precisionInfo.value != UNSPECIFIED;
154 /** @brief Logical negation operator */
155 bool operator!() const noexcept {
156 return precisionInfo.value == UNSPECIFIED;
159 /** @brief Cast operator to a ePrecision */
160 operator Precision::ePrecision() const noexcept {
161 return precisionInfo.value;
163 constexpr uint8_t getPrecVal() const noexcept {
164 return precisionInfo.value;
167 /** @brief Getter of precision name */
168 const char* name() const noexcept {
169 return precisionInfo.name;
172 /** @brief Creates from string with precision name */
173 static Precision FromStr(const std::string& str) {
174 static std::unordered_map<std::string, ePrecision> names = {
175 #define PRECISION_NAME(s) {#s, s}
176 PRECISION_NAME(Q78), PRECISION_NAME(U8), PRECISION_NAME(I8), PRECISION_NAME(I16),
177 PRECISION_NAME(I32), PRECISION_NAME(I64), PRECISION_NAME(U16), PRECISION_NAME(FP32),
178 PRECISION_NAME(FP16), PRECISION_NAME(MIXED), PRECISION_NAME(BIN), PRECISION_NAME(BOOL),
179 #undef PRECISION_NAME
181 auto i = names.find(str);
182 return i == names.end() ? Precision() : Precision(i->second);
186 * @brief Returns size of single element of that precision in bits
188 * @returns Number of bytes per element
190 size_t size() const {
191 if (precisionInfo.bitsSize == 0) {
192 THROW_IE_EXCEPTION << " cannot estimate element if precision is " << precisionInfo.name;
194 return precisionInfo.bitsSize >> 3;
197 /** @brief Checks if it is a floating point */
198 bool is_float() const noexcept {
199 return precisionInfo.isFloat;
202 bool isSigned() const noexcept {
203 return (precisionInfo.value == Precision::UNSPECIFIED) || (precisionInfo.value == Precision::MIXED) ||
204 (precisionInfo.value == Precision::FP32) || (precisionInfo.value == Precision::FP16) ||
205 (precisionInfo.value == Precision::Q78) || (precisionInfo.value == Precision::I16) ||
206 (precisionInfo.value == Precision::I8) || (precisionInfo.value == Precision::I32) ||
207 (precisionInfo.value == Precision::I64) || (precisionInfo.value == Precision::BIN) ||
208 (precisionInfo.value == Precision::CUSTOM);
213 * @brief Returns PrecisionInfo by its name
215 * @param name Name of precision
217 template <Precision::ePrecision precision>
218 static PrecisionInfo makePrecisionInfo(const char* name);
221 * @brief Compare two c-strings
223 * @param l Const pointer to first string
224 * @param r Const pointer to another string
225 * @returns True if strings are the same
227 static bool areSameStrings(const char* l, const char* r) noexcept {
228 if (l == r) return true;
230 if (l == nullptr || r == nullptr) return false;
232 for (; *l && *r; l++, r++) {
233 if (*l != *r) return false;
239 * @brief Return PrecisionInfo
241 static PrecisionInfo getPrecisionInfo(ePrecision v) {
244 return makePrecisionInfo<x>(#x);
259 return makePrecisionInfo<UNSPECIFIED>("UNSPECIFIED");
266 * @brief Particular precision traits
268 template <Precision::ePrecision p>
269 struct PrecisionTrait {};
271 /** @cond INTERNAL */
273 struct PrecisionTrait<Precision::FP32> {
274 using value_type = float;
278 struct PrecisionTrait<Precision::FP16> {
279 using value_type = int16_t;
282 struct PrecisionTrait<Precision::Q78> {
283 using value_type = uint16_t;
286 struct PrecisionTrait<Precision::I16> {
287 using value_type = int16_t;
290 struct PrecisionTrait<Precision::U16> {
291 using value_type = uint16_t;
294 struct PrecisionTrait<Precision::U8> {
295 using value_type = uint8_t;
298 struct PrecisionTrait<Precision::I8> {
299 using value_type = int8_t;
302 struct PrecisionTrait<Precision::BOOL> {
303 using value_type = uint8_t;
306 struct PrecisionTrait<Precision::I32> {
307 using value_type = int32_t;
310 struct PrecisionTrait<Precision::I64> {
311 using value_type = int64_t;
314 struct PrecisionTrait<Precision::BIN> {
315 using value_type = int8_t;
319 inline uint8_t type_size_or_zero() {
324 struct PrecisionTrait<Precision::UNSPECIFIED> {
325 using value_type = void;
329 struct PrecisionTrait<Precision::MIXED> : PrecisionTrait<Precision::UNSPECIFIED> {};
332 inline uint8_t type_size_or_zero<void>() {
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,
344 template <Precision::ePrecision T>
345 inline typename std::enable_if<!std::is_same<std::integral_constant<Precision::ePrecision, Precision::FP16>,
346 std::integral_constant<Precision::ePrecision, T>>::value,
349 return std::is_floating_point<typename PrecisionTrait<T>::value_type>::value;
352 template <Precision::ePrecision precision>
353 inline Precision::PrecisionInfo Precision::makePrecisionInfo(const char* name) {
354 Precision::PrecisionInfo info;
357 size_t nBits = precision == BIN ? 1 : 8;
358 info.bitsSize = nBits * type_size_or_zero<typename PrecisionTrait<precision>::value_type>();
359 info.isFloat = is_floating<precision>();
360 info.value = precision;
364 inline std::ostream& operator<<(std::ostream& out, const InferenceEngine::Precision& p) {
365 return out << p.name();
368 inline std::ostream& operator<<(std::ostream& out, const InferenceEngine::Precision::ePrecision& p) {
369 return out << Precision(p).name();
372 inline std::ostream& operator<<(std::ostream& os, const std::vector<Precision>& values) {
374 for (size_t i = 0; i < values.size(); ++i) {
376 if (i != (values.size() - 1ul)) {
384 inline constexpr uint32_t getPrecisionMask(
385 InferenceEngine::Precision::ePrecision precision1, InferenceEngine::Precision::ePrecision precision2,
386 InferenceEngine::Precision::ePrecision precision3 = InferenceEngine::Precision::MIXED,
387 InferenceEngine::Precision::ePrecision precision4 = InferenceEngine::Precision::MIXED) {
388 return (precision1) | (precision2 << 8) | (precision3 << 16) | (precision4 << 24);
393 } // namespace InferenceEngine