forked from openvinotoolkit/openvino
-
Notifications
You must be signed in to change notification settings - Fork 0
/
precision_utils.h
180 lines (150 loc) · 6.21 KB
/
precision_utils.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
/**
* @brief Basic functions to convert from FP16 to FP32 and vice versa
* @file precision_utils.h
*/
#pragma once
#include <algorithm>
#include <cstddef>
#include <limits>
#include <type_traits>
#include "ie_api.h"
/**
* @brief Inference Engine Plugin API namespace
*/
namespace InferenceEngine {
/**
* @brief A type difinition for FP16 data type. Defined as a singed short
* @ingroup ie_dev_api_precision
*/
using ie_fp16 = short;
/**
* @brief Namespace for precision utilities
* @ingroup ie_dev_api_precision
*/
namespace PrecisionUtils {
/**
* @brief Converts a single-precision floating point value to a half-precision floating poit value
* @ingroup ie_dev_api_precision
*
* @param[in] x A single-precision floating point value
* @return A half-precision floating point value
*/
INFERENCE_ENGINE_API_CPP(ie_fp16) f32tof16(float x);
/**
* @brief Convers a half-precision floating point value to a single-precision floating point value
* @ingroup ie_dev_api_precision
*
* @param[in] x A half-precision floating point value
* @return A single-precision floating point value
*/
INFERENCE_ENGINE_API_CPP(float) f16tof32(ie_fp16 x);
/**
* @brief Converts a half-precision floating point array to single-precision floating point array
* and applies `scale` and `bias` is needed
* @ingroup ie_dev_api_precision
*
* @param dst A destination array of single-precision floating point values
* @param[in] src A source array of half-precision floating point values
* @param[in] nelem A number of elements in arrays
* @param[in] scale An optional scale parameter
* @param[in] bias An optional bias parameter
*/
INFERENCE_ENGINE_API_CPP(void)
f16tof32Arrays(float* dst, const ie_fp16* src, size_t nelem, float scale = 1.f, float bias = 0.f);
/**
* @brief Converts a single-precision floating point array to a half-precision floating point array
* and applies `scale` and `bias` if needed
* @ingroup ie_dev_api_precision
*
* @param dst A destination array of half-precision floating point values
* @param[in] src A sources array of single-precision floating point values
* @param[in] nelem A number of elements in arrays
* @param[in] scale An optional scale parameter
* @param[in] bias An optional bias parameter
*/
INFERENCE_ENGINE_API_CPP(void)
f32tof16Arrays(ie_fp16* dst, const float* src, size_t nelem, float scale = 1.f, float bias = 0.f);
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4018)
#endif
namespace details {
// To overcame syntax parse error, when `>` comparison operator is threated as template closing bracket
constexpr inline bool Greater(size_t v1, size_t v2) {
return v1 > v2;
}
} // namespace details
/**
* @brief Converts one integral type to another saturating the result if the source value doesn't fit
* into destination type range
* @ingroup ie_dev_api_precision
*
* @param value Value to be converted
* @return A saturated value
*/
template <class OutT,
class InT,
typename std::enable_if<std::is_integral<OutT>::value && std::is_integral<InT>::value &&
std::is_signed<InT>::value && !std::is_same<OutT, InT>::value>::type* = nullptr>
inline OutT saturate_cast(const InT& value) {
using MaxT = typename std::conditional<details::Greater(sizeof(OutT), sizeof(InT)),
typename std::make_unsigned<OutT>::type,
typename std::make_unsigned<InT>::type>::type;
using MinT = typename std::conditional<details::Greater(sizeof(OutT), sizeof(InT)),
typename std::make_signed<OutT>::type,
typename std::make_signed<InT>::type>::type;
static const MaxT OUT_MAX = static_cast<MaxT>(std::numeric_limits<OutT>::max());
static const MaxT IN_MAX = static_cast<MaxT>(std::numeric_limits<InT>::max());
static const MinT OUT_MIN = static_cast<MinT>(std::numeric_limits<OutT>::min());
static const MinT IN_MIN = static_cast<MinT>(std::numeric_limits<InT>::min());
if (OUT_MAX > IN_MAX && OUT_MIN < IN_MIN) {
return static_cast<OutT>(value);
}
const InT max = static_cast<InT>(OUT_MAX < IN_MAX ? OUT_MAX : IN_MAX);
const InT min = static_cast<InT>(OUT_MIN > IN_MIN ? OUT_MIN : IN_MIN);
return static_cast<OutT>(std::min(std::max(value, min), max));
}
/**
* @brief Converts one integral type to another saturating the result if the source value doesn't fit
* into destination type range
* @ingroup ie_dev_api_precision
*
* @param value Value to be converted
* @return A saturated value
*/
template <class OutT,
class InT,
typename std::enable_if<std::is_integral<OutT>::value && std::is_integral<InT>::value &&
std::is_unsigned<InT>::value && !std::is_same<OutT, InT>::value>::type* = nullptr>
inline OutT saturate_cast(const InT& value) {
using MaxT = typename std::conditional<details::Greater(sizeof(OutT), sizeof(InT)),
typename std::make_unsigned<OutT>::type,
typename std::make_unsigned<InT>::type>::type;
static const MaxT OUT_MAX = static_cast<MaxT>(std::numeric_limits<OutT>::max());
static const MaxT IN_MAX = static_cast<MaxT>(std::numeric_limits<InT>::max());
if (OUT_MAX > IN_MAX) {
return static_cast<OutT>(value);
}
const InT max = static_cast<InT>(OUT_MAX < IN_MAX ? OUT_MAX : IN_MAX);
return static_cast<OutT>(std::min(value, max));
}
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
/**
* @brief Converts one integral type to another saturating the result if the source value doesn't fit
* into destination type range
* @ingroup ie_dev_api_precision
*
* @param value Value to be converted
* @return A saturated value
*/
template <class InT>
inline InT saturate_cast(const InT& value) {
return value;
}
} // namespace PrecisionUtils
} // namespace InferenceEngine