blob: 8fa513eee1e61e442eae70589bcbe6166da27fd3 [file] [log] [blame]
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001/*
Pablo Marquez Tello9c8f9a92023-06-08 12:00:29 +01002 * Copyright (c) 2019-2023 Arm Limited.
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01003 *
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 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +000024#ifndef ARM_COMPUTE_QUANTIZATION_INFO_H
25#define ARM_COMPUTE_QUANTIZATION_INFO_H
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010026
Giorgio Arena433ea492021-05-26 15:32:50 +010027#include "arm_compute/core/Rounding.h"
Matthew Bentham7d9a78e2023-05-31 13:18:33 +000028#include "arm_compute/core/utils/misc/Utility.h"
Giorgio Arena433ea492021-05-26 15:32:50 +010029#include "support/ToolchainSupport.h"
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010030
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010031#include <vector>
32
33namespace arm_compute
34{
Michalis Spyrou8d4d1b82019-11-28 11:31:23 +000035using qasymm8_signed_t = int8_t; /**< 8 bit signed quantized asymmetric scalar value */
36using qasymm8_t = uint8_t; /**< 8 bit quantized asymmetric scalar value */
37using qsymm16_t = int16_t; /**< 16 bit quantized symmetric scalar value */
38using qasymm16_t = uint16_t; /**< 16 bit quantized asymmetric scalar value */
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010039
40/** Quantization info when assuming per layer quantization */
41struct UniformQuantizationInfo
42{
43 /** Default constructor */
44 UniformQuantizationInfo()
45 : scale(0.f), offset(0)
46 {
47 }
48 /** Constructor
49 *
50 * @param[in] scale Quantization scale
51 * @param[in] offset Quantization offset
52 */
53 UniformQuantizationInfo(float scale, int32_t offset)
54 : scale(scale), offset(offset)
55 {
56 }
57 /** Checks if the scale and offset are both zero */
58 bool empty() const
59 {
60 return (scale == 0) && (offset == 0);
61 }
62
63 float scale;
64 int32_t offset;
65};
66
67/** Quantization information */
Georgios Pinitas3d13af82019-06-04 13:04:16 +010068class QuantizationInfo
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010069{
Georgios Pinitas3d13af82019-06-04 13:04:16 +010070public:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010071 /** Default constructor */
72 QuantizationInfo() noexcept
Georgios Pinitas3d13af82019-06-04 13:04:16 +010073 : _scale(),
74 _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010075 {
76 }
77 /** Construct quantization info.
78 *
79 * @note Used for symmetric quantization
80 *
81 * @param[in] scale Scale.
82 */
83 QuantizationInfo(float scale)
Georgios Pinitas3d13af82019-06-04 13:04:16 +010084 : _scale(1, scale), _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010085 {
86 }
87 /** Construct quantization info.
88 *
89 * @note Used for asymmetric quantization
90 *
91 * @param[in] scale Scale.
92 * @param[in] offset Offset.
93 */
94 QuantizationInfo(float scale, int offset)
Georgios Pinitas3d13af82019-06-04 13:04:16 +010095 : _scale(1, scale), _offset(1, offset)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010096 {
97 }
98 /** Construct quantization info.
99 *
100 * @note Used for symmetric per channel quantization
101 *
102 * @param[in] scale Scale.
103 */
104 QuantizationInfo(std::vector<float> scale)
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100105 : _scale(scale), _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100106 {
107 }
Michalis Spyrou29a01c92019-08-22 11:44:04 +0100108 /** Construct quantization info.
109 *
110 * @note Used for asymmetric per channel quantization
111 *
112 * @param[in] scale Scale.
113 * @param[in] offset Offset.
114 */
115 QuantizationInfo(std::vector<float> scale, std::vector<int32_t> offset)
116 : _scale(scale), _offset(offset)
117 {
118 }
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100119 /** Scale vector accessor
120 *
121 * @return A reference to quantization scale metadata
122 */
123 const std::vector<float> &scale() const
124 {
125 return _scale;
126 }
127 /** Offset vector accessor
128 *
129 * @return A reference to quantization offset metadata
130 */
131 const std::vector<int32_t> &offset() const
132 {
133 return _offset;
134 }
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100135 /** Indicates whether this QuantizationInfo has valid settings or not
136 *
137 * @return True if the this has invalid settings.
138 */
139 bool empty() const
140 {
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100141 return _scale.empty() && _offset.empty();
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100142 }
143 /** Return per layer quantization info
144 *
145 * @return Uniform quantization information in case of empty information zero is returned in the respective fields
146 */
147 UniformQuantizationInfo uniform() const
148 {
149 UniformQuantizationInfo uqinfo;
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100150 uqinfo.scale = _scale.empty() ? 0 : _scale[0];
151 uqinfo.offset = _offset.empty() ? 0 : _offset[0];
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100152
153 return uqinfo;
154 }
155
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100156private:
157 std::vector<float> _scale; /**< Vector containing scaling factors */
158 std::vector<int32_t> _offset; /**< Vector containing zero offsets */
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100159};
160
161/** Check whether two quantization info are equal.
162 *
163 * @param[in] lhs RHS quantization info.
164 * @param[in] rhs LHS quantization info.
165 *
166 * @return True if the given quantization info is the same.
167 */
168inline bool operator==(const QuantizationInfo &lhs, const QuantizationInfo &rhs)
169{
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100170 return (lhs.scale() == rhs.scale()) && (lhs.offset() == rhs.offset());
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100171}
172
173/** Check whether two quantization info are not equal.
174 *
175 * @param[in] lhs RHS quantization info.
176 * @param[in] rhs LHS quantization info.
177 *
178 * @return True if the given quantization info is the same.
179 */
180inline bool operator!=(const QuantizationInfo &lhs, const QuantizationInfo &rhs)
181{
182 return !(operator==(lhs, rhs));
183}
184
185/** Check whether two quantization info are equal.
186 *
187 * @param[in] lhs RHS quantization info.
188 * @param[in] rhs LHS quantization info.
189 *
190 * @return True if the given quantization info is the same.
191 */
192inline bool operator==(const UniformQuantizationInfo &lhs, const UniformQuantizationInfo &rhs)
193{
194 return (lhs.scale == rhs.scale) && (lhs.offset == rhs.offset);
195}
196
197/** Check whether two quantization info are not equal.
198 *
199 * @param[in] lhs RHS quantization info.
200 * @param[in] rhs LHS quantization info.
201 *
202 * @return True if the given quantization info is the same.
203 */
204inline bool operator!=(const UniformQuantizationInfo &lhs, const UniformQuantizationInfo &rhs)
205{
206 return !(operator==(lhs, rhs));
207}
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000208template <typename QUANTIZED_TYPE = uint8_t>
209struct Qasymm8QuantizationHelper
210{
211 static_assert(std::is_same<QUANTIZED_TYPE, uint8_t>::value
212 || std::is_same<QUANTIZED_TYPE, int8_t>::value,
213 "quantized type should be either uint8_t or int8_t.");
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100214
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000215 /** Quantize a value given a 8-bit asymmetric quantization scheme
216 *
Giorgio Arena433ea492021-05-26 15:32:50 +0100217 * @param[in] value Value to quantize
218 * @param[in] qinfo Quantization information to use for quantizing
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000219 *
220 * @return Quantized value
221 */
Giorgio Arena433ea492021-05-26 15:32:50 +0100222 static inline QUANTIZED_TYPE quantize(float value, const UniformQuantizationInfo &qinfo)
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000223 {
224 ARM_COMPUTE_ERROR_ON(qinfo.scale == 0);
Giorgio Arena433ea492021-05-26 15:32:50 +0100225 const int quantized = support::cpp11::lround(value / qinfo.scale) + qinfo.offset;
226 return static_cast<QUANTIZED_TYPE>(arm_compute::utility::clamp<decltype(quantized), QUANTIZED_TYPE>(quantized));
227 }
228
229 /** Quantize a value given a 8-bit asymmetric quantization scheme using a specific rounding policy
230 *
231 * @param[in] value Value to quantize
232 * @param[in] qinfo Quantization information to use for quantizing
233 * @param[in] rounding_policy Rounding policy to use
234 *
235 * @return Quantized value
236 */
237 static inline QUANTIZED_TYPE quantize(float value, const UniformQuantizationInfo &qinfo, RoundingPolicy rounding_policy)
238 {
239 if(rounding_policy == RoundingPolicy::TO_NEAREST_UP)
240 {
241 return quantize(value, qinfo);
242 }
243
244 ARM_COMPUTE_ERROR_ON(qinfo.scale == 0);
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000245 const int quantized = arm_compute::round(value / qinfo.scale, rounding_policy) + qinfo.offset;
246 return static_cast<QUANTIZED_TYPE>(arm_compute::utility::clamp<decltype(quantized), QUANTIZED_TYPE>(quantized));
247 }
248
249 /** Quantize a value given a 8-bit asymmetric quantization scheme
250 *
251 * @param[in] value Value to quantize
252 * @param[in] qinfo Quantization information to use for quantizing
253 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
254 *
255 * @return Quantized value
256 */
257 static inline QUANTIZED_TYPE quantize(float value, const QuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
258 {
259 const UniformQuantizationInfo uqinfo = qinfo.uniform();
260 ARM_COMPUTE_ERROR_ON(uqinfo.scale == 0);
261 const int quantized = arm_compute::round(value / uqinfo.scale, rounding_policy) + uqinfo.offset;
262 return static_cast<QUANTIZED_TYPE>(arm_compute::utility::clamp<decltype(quantized), QUANTIZED_TYPE>(quantized));
263 }
264
265 /** Dequantize a value given a 8-bit asymmetric quantization scheme
266 *
267 * @param[in] value Value to dequantize
268 * @param[in] qinfo Quantization information to use for dequantizing
269 *
270 * @return Dequantized value
271 */
272 static inline float dequantize(QUANTIZED_TYPE value, const UniformQuantizationInfo &qinfo)
273 {
274 return (static_cast<int>(value) - qinfo.offset) * qinfo.scale;
275 }
276
277 /** Dequantize a value given a 8-bit asymmetric quantization scheme
278 *
279 * @param[in] value Value to dequantize
280 * @param[in] qinfo Quantization information to use for dequantizing
281 *
282 * @return Dequantized value
283 */
284 static inline float dequantize(QUANTIZED_TYPE value, const QuantizationInfo &qinfo)
285 {
286 const UniformQuantizationInfo uqinfo = qinfo.uniform();
287 return (static_cast<int>(value) - uqinfo.offset) * uqinfo.scale;
288 }
289};
290
291/** Quantize a value given an unsigned 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100292 *
293 * @param[in] value Value to quantize
294 * @param[in] qinfo Quantization information to use for quantizing
295 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
296 *
297 * @return Quantized value
298 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000299template <typename INFO_TYPE>
300inline uint8_t quantize_qasymm8(float value, const INFO_TYPE &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100301{
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000302 return Qasymm8QuantizationHelper<uint8_t>::quantize(value, qinfo, rounding_policy);
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100303}
304
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000305/** Quantize a value given a signed 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100306 *
307 * @param[in] value Value to quantize
308 * @param[in] qinfo Quantization information to use for quantizing
309 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
310 *
311 * @return Quantized value
312 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000313template <typename INFO_TYPE>
314inline int8_t quantize_qasymm8_signed(float value, const INFO_TYPE &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100315{
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000316 return Qasymm8QuantizationHelper<int8_t>::quantize(value, qinfo, rounding_policy);
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100317}
318
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100319/** Quantize a value given a 8-bit symmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100320 *
321 * @param[in] value Value to quantize
322 * @param[in] qinfo Quantization information to use for quantizing
323 *
324 * @return Quantized value
325 */
326inline int8_t quantize_qsymm8(float value, const QuantizationInfo &qinfo)
327{
328 int quantized = arm_compute::round(value / qinfo.uniform().scale, RoundingPolicy::TO_NEAREST_UP);
329 quantized = std::max(-128, std::min(quantized, 127));
330 return quantized;
331}
332
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100333/** Quantize a value given a 8-bit symmetric per channel quantization scheme
334 *
335 * @param[in] value Value to quantize
336 * @param[in] qinfo Quantization information to use for quantizing
337 * @param[in] channel_id channel index into the scale vector of quantization info
338 *
339 * @return Quantized value
340 */
341inline int8_t quantize_qsymm8_per_channel(float value, const QuantizationInfo &qinfo, size_t channel_id = 0)
342{
343 int quantized = arm_compute::round(value / qinfo.scale()[channel_id], RoundingPolicy::TO_NEAREST_UP);
344 quantized = std::max(-128, std::min(quantized, 127));
345 return quantized;
346}
347
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000348/** Dequantize a value given an unsigned 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100349 *
350 * @param[in] value Value to dequantize
351 * @param[in] qinfo Quantization information to use for dequantizing
352 *
353 * @return Dequantized value
354 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000355template <typename INFO_TYPE>
356inline float dequantize_qasymm8(uint8_t value, const INFO_TYPE &qinfo)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100357{
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000358 return Qasymm8QuantizationHelper<uint8_t>::dequantize(value, qinfo);
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100359}
360
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000361/** Dequantize a value given a signed 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100362 *
363 * @param[in] value Value to dequantize
364 * @param[in] qinfo Quantization information to use for dequantizing
365 *
366 * @return Dequantized value
367 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000368template <typename INFO_TYPE>
369inline float dequantize_qasymm8_signed(int8_t value, const INFO_TYPE &qinfo)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100370{
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000371 return Qasymm8QuantizationHelper<int8_t>::dequantize(value, qinfo);
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100372}
373
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100374/** Dequantize a value given an 8-bit asymmetric quantization scheme
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100375 *
376 * @param[in] value Value to dequantize
377 * @param[in] scale Scale to use for dequantization
378 * @param[in] offset Zero-offset to use for dequantization
379 *
380 * @return Dequantized value
381 */
382inline float dequantize(uint8_t value, float scale, int32_t offset)
383{
384 return (static_cast<int>(value) - offset) * scale;
385}
386
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100387/** Dequantize a value given a 8-bit symmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100388 *
389 * @param[in] value Value to dequantize
390 * @param[in] qinfo Quantization information to use for dequantizing
391 *
392 * @return Dequantized value
393 */
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100394inline float dequantize_qsymm8(int8_t value, const UniformQuantizationInfo &qinfo)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100395{
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100396 return value * qinfo.scale;
397}
398
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100399/** Dequantize a value given a 8-bit symmetric quantization scheme
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100400 *
401 * @param[in] value Value to dequantize
402 * @param[in] scale Scale to use for dequantization
403 *
404 * @return Dequantized value
405 */
406inline float dequantize(int8_t value, float scale)
407{
408 return value * scale;
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100409}
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100410
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100411/** Dequantize a value given a 16-bit symmetric quantization scheme
Manuel Bottini10c53f12019-07-17 16:11:53 +0100412 *
413 * @param[in] value Value to dequantize
414 * @param[in] scale Scale to use for dequantization
415 *
416 * @return Dequantized value
417 */
418inline float dequantize(int16_t value, float scale)
419{
420 return value * scale;
421}
422
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100423/** Dequantize a value given a 16-bit asymmetric quantization scheme
424 *
425 * @param[in] value Value to dequantize
426 * @param[in] scale Scale to use for dequantization
427 * @param[in] offset Zero-offset to use for dequantization
428 *
429 * @return Dequantized value
430 */
431inline float dequantize(uint16_t value, float scale, int32_t offset)
432{
433 return (static_cast<int>(value) - offset) * scale;
434}
435
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100436/** Quantize a value given a 16-bit symmetric quantization scheme
437 *
438 * @param[in] value Value to quantize
439 * @param[in] qinfo Quantization information to use for quantizing
440 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
441 *
442 * @return Quantized value
443 */
444inline int16_t quantize_qsymm16(float value, const UniformQuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
445{
446 int quantized = arm_compute::round(value / qinfo.scale, rounding_policy);
447 quantized = arm_compute::utility::clamp<int, int16_t>(quantized);
448 return quantized;
449}
450
451/** Dequantize a value given a 16-bit symmetric quantization scheme
452 *
453 * @param[in] value Value to dequantize
454 * @param[in] qinfo Quantization information to use for dequantizing
455 *
456 * @return Dequantized value
457 */
458inline float dequantize_qsymm16(int16_t value, const UniformQuantizationInfo &qinfo)
459{
460 return value * qinfo.scale;
461}
462
463/** Quantize a value given a 16-bit symmetric quantization scheme
464 *
465 * @param[in] value Value to quantize
466 * @param[in] qinfo Quantization information to use for quantizing
467 *
468 * @return Quantized value
469 */
470inline int16_t quantize_qsymm16(float value, const QuantizationInfo &qinfo)
471{
472 return quantize_qsymm16(value, qinfo.uniform());
473}
474
475/** Dequantize a value given a 16-bit symmetric quantization scheme
476 *
477 * @param[in] value Value to dequantize
478 * @param[in] qinfo Quantization information to use for dequantizing
479 *
480 * @return Dequantized value
481 */
482inline float dequantize_qsymm16(int16_t value, const QuantizationInfo &qinfo)
483{
484 return dequantize_qsymm16(value, qinfo.uniform());
485}
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100486
487/** Quantize a value given a 16-bit asymmetric quantization scheme
488 *
489 * @param[in] value Value to quantize
490 * @param[in] qinfo Quantization information to use for quantizing
491 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
492 *
493 * @return Quantized value
494 */
495inline uint16_t quantize_qasymm16(float value, const UniformQuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
496{
497 int quantized = arm_compute::round(value / qinfo.scale, rounding_policy) + qinfo.offset;
498 quantized = arm_compute::utility::clamp<int, uint16_t>(quantized);
499 return quantized;
500}
501
502/** Dequantize a value given a 16-bit asymmetric quantization scheme
503 *
504 * @param[in] value Value to dequantize
505 * @param[in] qinfo Quantization information to use for dequantizing
506 *
507 * @return Dequantized value
508 */
509inline float dequantize_qasymm16(uint16_t value, const UniformQuantizationInfo &qinfo)
510{
511 return (static_cast<int>(value) - qinfo.offset) * qinfo.scale;
512}
513
514/** Quantize a value given a 16-bit asymmetric quantization scheme
515 *
516 * @param[in] value Value to quantize
517 * @param[in] qinfo Quantization information to use for quantizing
518 *
519 * @return Quantized value
520 */
521inline uint16_t quantize_qasymm16(float value, const QuantizationInfo &qinfo)
522{
523 return quantize_qasymm16(value, qinfo.uniform());
524}
525
526/** Dequantize a value given a 16-bit asymmetric quantization scheme
527 *
528 * @param[in] value Value to dequantize
529 * @param[in] qinfo Quantization information to use for dequantizing
530 *
531 * @return Dequantized value
532 */
533inline float dequantize_qasymm16(uint16_t value, const QuantizationInfo &qinfo)
534{
535 return dequantize_qasymm16(value, qinfo.uniform());
536}
Manuel Bottini4370cff2020-02-07 16:31:59 +0000537
538/*
539 * In case of requantization of a quantized input tensor to an output tensor with another quantization
540 * instead of applying dequantization and then a quantization functions, we just compute new scale and
541 * offset.
542 *
543 * Assuming:
544 * - q_i as input quantized value
545 * - q_o as output quantized value
546 * - z_i as input quantization offset value
547 * - z_o as output quantization offset value
548 * - s_i as input quantization scale value
549 * - s_o as output quantization scale value
550 * - z_n as new quantization offset value
551 * - s_n as new quantization scale value
552 *
553 * q_o = ( q_i - z_i ) * s_i / s_o + z_o
554 *
555 * We can rewrite the formula as:
556 *
557 * q_o = ( q_i * s_i / s_o ) - z_i * s_i / s_o + z_o
558 *
559 * q_o = q_i / s_n + z_n
560 *
561 * Where:
562 *
563 * s_n = s_o / s_i
564 *
565 * z_n = - z_i * s_i / s_o + z_o
566 *
567 */
568inline UniformQuantizationInfo compute_requantization_scale_offset(const UniformQuantizationInfo &uqinfo_in, const UniformQuantizationInfo &uqinfo_out)
569{
570 float scale_to_apply = uqinfo_out.scale;
571 int32_t offset_to_apply = uqinfo_out.offset;
572
573 scale_to_apply /= uqinfo_in.scale;
574 // In order to minimize flooring we convert the offset to a float,
575 // then compute the new offset in the float domain,
576 // finally we convert it back as int32_t
577 offset_to_apply -= static_cast<int32_t>(static_cast<float>(uqinfo_in.offset) * uqinfo_in.scale / uqinfo_out.scale);
578 return UniformQuantizationInfo(scale_to_apply, offset_to_apply);
579}
580
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100581} // namespace arm_compute
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000582#endif /* ARM_COMPUTE_QUANTIZATION_INFO_H */