blob: dcfdd6ba16b610f80203fa2aaa43886ff300a57c [file] [log] [blame]
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001/*
2 * Copyright (c) 2019 ARM Limited.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#ifndef __ARM_COMPUTE_QUANTIZATION_INFO_H__
25#define __ARM_COMPUTE_QUANTIZATION_INFO_H__
26
27#include "arm_compute/core/Rounding.h"
Manuel Bottini3689fcd2019-06-14 17:18:12 +010028#include "utils/misc/Utility.h"
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010029
30#include <cstddef>
31#include <vector>
32
33namespace arm_compute
34{
35using qasymm8_t = uint8_t; /**< 8 bit quantized asymmetric scalar value */
36using qsymm8_t = int8_t; /**< 8 bit quantized symmetric scalar value */
37
38/** Quantization info when assuming per layer quantization */
39struct UniformQuantizationInfo
40{
41 /** Default constructor */
42 UniformQuantizationInfo()
43 : scale(0.f), offset(0)
44 {
45 }
46 /** Constructor
47 *
48 * @param[in] scale Quantization scale
49 * @param[in] offset Quantization offset
50 */
51 UniformQuantizationInfo(float scale, int32_t offset)
52 : scale(scale), offset(offset)
53 {
54 }
55 /** Checks if the scale and offset are both zero */
56 bool empty() const
57 {
58 return (scale == 0) && (offset == 0);
59 }
60
61 float scale;
62 int32_t offset;
63};
64
65/** Quantization information */
Georgios Pinitas3d13af82019-06-04 13:04:16 +010066class QuantizationInfo
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010067{
Georgios Pinitas3d13af82019-06-04 13:04:16 +010068public:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010069 /** Default constructor */
70 QuantizationInfo() noexcept
Georgios Pinitas3d13af82019-06-04 13:04:16 +010071 : _scale(),
72 _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010073 {
74 }
75 /** Construct quantization info.
76 *
77 * @note Used for symmetric quantization
78 *
79 * @param[in] scale Scale.
80 */
81 QuantizationInfo(float scale)
Georgios Pinitas3d13af82019-06-04 13:04:16 +010082 : _scale(1, scale), _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010083 {
84 }
85 /** Construct quantization info.
86 *
87 * @note Used for asymmetric quantization
88 *
89 * @param[in] scale Scale.
90 * @param[in] offset Offset.
91 */
92 QuantizationInfo(float scale, int offset)
Georgios Pinitas3d13af82019-06-04 13:04:16 +010093 : _scale(1, scale), _offset(1, offset)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010094 {
95 }
96 /** Construct quantization info.
97 *
98 * @note Used for symmetric per channel quantization
99 *
100 * @param[in] scale Scale.
101 */
102 QuantizationInfo(std::vector<float> scale)
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100103 : _scale(scale), _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100104 {
105 }
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100106 /** Scale vector accessor
107 *
108 * @return A reference to quantization scale metadata
109 */
110 const std::vector<float> &scale() const
111 {
112 return _scale;
113 }
114 /** Offset vector accessor
115 *
116 * @return A reference to quantization offset metadata
117 */
118 const std::vector<int32_t> &offset() const
119 {
120 return _offset;
121 }
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100122 /** Indicates whether this QuantizationInfo has valid settings or not
123 *
124 * @return True if the this has invalid settings.
125 */
126 bool empty() const
127 {
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100128 return _scale.empty() && _offset.empty();
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100129 }
130 /** Return per layer quantization info
131 *
132 * @return Uniform quantization information in case of empty information zero is returned in the respective fields
133 */
134 UniformQuantizationInfo uniform() const
135 {
136 UniformQuantizationInfo uqinfo;
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100137 uqinfo.scale = _scale.empty() ? 0 : _scale[0];
138 uqinfo.offset = _offset.empty() ? 0 : _offset[0];
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100139
140 return uqinfo;
141 }
142
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100143private:
144 std::vector<float> _scale; /**< Vector containing scaling factors */
145 std::vector<int32_t> _offset; /**< Vector containing zero offsets */
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100146};
147
148/** Check whether two quantization info are equal.
149 *
150 * @param[in] lhs RHS quantization info.
151 * @param[in] rhs LHS quantization info.
152 *
153 * @return True if the given quantization info is the same.
154 */
155inline bool operator==(const QuantizationInfo &lhs, const QuantizationInfo &rhs)
156{
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100157 return (lhs.scale() == rhs.scale()) && (lhs.offset() == rhs.offset());
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100158}
159
160/** Check whether two quantization info are not equal.
161 *
162 * @param[in] lhs RHS quantization info.
163 * @param[in] rhs LHS quantization info.
164 *
165 * @return True if the given quantization info is the same.
166 */
167inline bool operator!=(const QuantizationInfo &lhs, const QuantizationInfo &rhs)
168{
169 return !(operator==(lhs, rhs));
170}
171
172/** Check whether two quantization info are equal.
173 *
174 * @param[in] lhs RHS quantization info.
175 * @param[in] rhs LHS quantization info.
176 *
177 * @return True if the given quantization info is the same.
178 */
179inline bool operator==(const UniformQuantizationInfo &lhs, const UniformQuantizationInfo &rhs)
180{
181 return (lhs.scale == rhs.scale) && (lhs.offset == rhs.offset);
182}
183
184/** Check whether two quantization info are not equal.
185 *
186 * @param[in] lhs RHS quantization info.
187 * @param[in] rhs LHS quantization info.
188 *
189 * @return True if the given quantization info is the same.
190 */
191inline bool operator!=(const UniformQuantizationInfo &lhs, const UniformQuantizationInfo &rhs)
192{
193 return !(operator==(lhs, rhs));
194}
195
196/** Quantize a value given a asymmetric quantization scheme
197 *
198 * @param[in] value Value to quantize
199 * @param[in] qinfo Quantization information to use for quantizing
200 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
201 *
202 * @return Quantized value
203 */
204inline uint8_t quantize_qasymm8(float value, const UniformQuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
205{
206 int quantized = arm_compute::round(value / qinfo.scale, rounding_policy) + qinfo.offset;
207 quantized = std::max(0, std::min(quantized, 255));
208 return quantized;
209}
210
211/** Quantize a value given a asymmetric quantization scheme
212 *
213 * @param[in] value Value to quantize
214 * @param[in] qinfo Quantization information to use for quantizing
215 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
216 *
217 * @return Quantized value
218 */
219inline uint8_t quantize_qasymm8(float value, const QuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
220{
221 UniformQuantizationInfo uqinfo = qinfo.uniform();
222 int quantized = arm_compute::round(value / uqinfo.scale, rounding_policy) + uqinfo.offset;
223 quantized = std::max(0, std::min(quantized, 255));
224 return quantized;
225}
226
227/** Quantize a value given a symmetric quantization scheme
228 *
229 * @param[in] value Value to quantize
230 * @param[in] qinfo Quantization information to use for quantizing
231 *
232 * @return Quantized value
233 */
234inline int8_t quantize_qsymm8(float value, const QuantizationInfo &qinfo)
235{
236 int quantized = arm_compute::round(value / qinfo.uniform().scale, RoundingPolicy::TO_NEAREST_UP);
237 quantized = std::max(-128, std::min(quantized, 127));
238 return quantized;
239}
240
241/** Dequantize a value given a asymmetric quantization scheme
242 *
243 * @param[in] value Value to dequantize
244 * @param[in] qinfo Quantization information to use for dequantizing
245 *
246 * @return Dequantized value
247 */
248inline float dequantize_qasymm8(uint8_t value, const UniformQuantizationInfo &qinfo)
249{
250 return (static_cast<int>(value) - qinfo.offset) * qinfo.scale;
251}
252
253/** Dequantize a value given a asymmetric quantization scheme
254 *
255 * @param[in] value Value to dequantize
256 * @param[in] qinfo Quantization information to use for dequantizing
257 *
258 * @return Dequantized value
259 */
260inline float dequantize_qasymm8(uint8_t value, const QuantizationInfo &qinfo)
261{
262 UniformQuantizationInfo uqinfo = qinfo.uniform();
263 return (static_cast<int>(value) - uqinfo.offset) * uqinfo.scale;
264}
265
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100266/** Dequantize a value given an asymmetric quantization scheme
267 *
268 * @param[in] value Value to dequantize
269 * @param[in] scale Scale to use for dequantization
270 * @param[in] offset Zero-offset to use for dequantization
271 *
272 * @return Dequantized value
273 */
274inline float dequantize(uint8_t value, float scale, int32_t offset)
275{
276 return (static_cast<int>(value) - offset) * scale;
277}
278
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100279/** Dequantize a value given a symmetric quantization scheme
280 *
281 * @param[in] value Value to dequantize
282 * @param[in] qinfo Quantization information to use for dequantizing
283 *
284 * @return Dequantized value
285 */
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100286inline float dequantize_qsymm8(int8_t value, const UniformQuantizationInfo &qinfo)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100287{
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100288 return value * qinfo.scale;
289}
290
291/** Dequantize a value given a symmetric quantization scheme
292 *
293 * @param[in] value Value to dequantize
294 * @param[in] scale Scale to use for dequantization
295 *
296 * @return Dequantized value
297 */
298inline float dequantize(int8_t value, float scale)
299{
300 return value * scale;
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100301}
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100302
303/** Quantize a value given a 16-bit symmetric quantization scheme
304 *
305 * @param[in] value Value to quantize
306 * @param[in] qinfo Quantization information to use for quantizing
307 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
308 *
309 * @return Quantized value
310 */
311inline int16_t quantize_qsymm16(float value, const UniformQuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
312{
313 int quantized = arm_compute::round(value / qinfo.scale, rounding_policy);
314 quantized = arm_compute::utility::clamp<int, int16_t>(quantized);
315 return quantized;
316}
317
318/** Dequantize a value given a 16-bit symmetric quantization scheme
319 *
320 * @param[in] value Value to dequantize
321 * @param[in] qinfo Quantization information to use for dequantizing
322 *
323 * @return Dequantized value
324 */
325inline float dequantize_qsymm16(int16_t value, const UniformQuantizationInfo &qinfo)
326{
327 return value * qinfo.scale;
328}
329
330/** Quantize a value given a 16-bit symmetric quantization scheme
331 *
332 * @param[in] value Value to quantize
333 * @param[in] qinfo Quantization information to use for quantizing
334 *
335 * @return Quantized value
336 */
337inline int16_t quantize_qsymm16(float value, const QuantizationInfo &qinfo)
338{
339 return quantize_qsymm16(value, qinfo.uniform());
340}
341
342/** Dequantize a value given a 16-bit symmetric quantization scheme
343 *
344 * @param[in] value Value to dequantize
345 * @param[in] qinfo Quantization information to use for dequantizing
346 *
347 * @return Dequantized value
348 */
349inline float dequantize_qsymm16(int16_t value, const QuantizationInfo &qinfo)
350{
351 return dequantize_qsymm16(value, qinfo.uniform());
352}
353
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100354} // namespace arm_compute
355#endif /*__ARM_COMPUTE_QUANTIZATION_INFO_H__ */