blob: 471b8c57aba6100f8962e270659ebd252968fd57 [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"
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010029
Giorgio Arena433ea492021-05-26 15:32:50 +010030#include "support/ToolchainSupport.h"
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010031
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010032#include <vector>
33
34namespace arm_compute
35{
Michalis Spyrou8d4d1b82019-11-28 11:31:23 +000036using qasymm8_signed_t = int8_t; /**< 8 bit signed quantized asymmetric scalar value */
37using qasymm8_t = uint8_t; /**< 8 bit quantized asymmetric scalar value */
38using qsymm16_t = int16_t; /**< 16 bit quantized symmetric scalar value */
39using qasymm16_t = uint16_t; /**< 16 bit quantized asymmetric scalar value */
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010040
41/** Quantization info when assuming per layer quantization */
42struct UniformQuantizationInfo
43{
44 /** Default constructor */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010045 UniformQuantizationInfo() : scale(0.f), offset(0)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010046 {
47 }
48 /** Constructor
49 *
50 * @param[in] scale Quantization scale
51 * @param[in] offset Quantization offset
52 */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010053 UniformQuantizationInfo(float scale, int32_t offset) : scale(scale), offset(offset)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010054 {
55 }
56 /** Checks if the scale and offset are both zero */
57 bool empty() const
58 {
59 return (scale == 0) && (offset == 0);
60 }
61
62 float scale;
63 int32_t offset;
64};
65
66/** Quantization information */
Georgios Pinitas3d13af82019-06-04 13:04:16 +010067class QuantizationInfo
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010068{
Georgios Pinitas3d13af82019-06-04 13:04:16 +010069public:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010070 /** Default constructor */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010071 QuantizationInfo() noexcept : _scale(), _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010072 {
73 }
74 /** Construct quantization info.
75 *
76 * @note Used for symmetric quantization
77 *
78 * @param[in] scale Scale.
79 */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010080 QuantizationInfo(float scale) : _scale(1, scale), _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010081 {
82 }
83 /** Construct quantization info.
84 *
85 * @note Used for asymmetric quantization
86 *
87 * @param[in] scale Scale.
88 * @param[in] offset Offset.
89 */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010090 QuantizationInfo(float scale, int offset) : _scale(1, scale), _offset(1, offset)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010091 {
92 }
93 /** Construct quantization info.
94 *
95 * @note Used for symmetric per channel quantization
96 *
97 * @param[in] scale Scale.
98 */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010099 QuantizationInfo(std::vector<float> scale) : _scale(scale), _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100100 {
101 }
Michalis Spyrou29a01c92019-08-22 11:44:04 +0100102 /** Construct quantization info.
103 *
104 * @note Used for asymmetric per channel quantization
105 *
106 * @param[in] scale Scale.
107 * @param[in] offset Offset.
108 */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100109 QuantizationInfo(std::vector<float> scale, std::vector<int32_t> offset) : _scale(scale), _offset(offset)
Michalis Spyrou29a01c92019-08-22 11:44:04 +0100110 {
111 }
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100112 /** Scale vector accessor
113 *
114 * @return A reference to quantization scale metadata
115 */
116 const std::vector<float> &scale() const
117 {
118 return _scale;
119 }
120 /** Offset vector accessor
121 *
122 * @return A reference to quantization offset metadata
123 */
124 const std::vector<int32_t> &offset() const
125 {
126 return _offset;
127 }
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100128 /** Indicates whether this QuantizationInfo has valid settings or not
129 *
130 * @return True if the this has invalid settings.
131 */
132 bool empty() const
133 {
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100134 return _scale.empty() && _offset.empty();
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100135 }
136 /** Return per layer quantization info
137 *
138 * @return Uniform quantization information in case of empty information zero is returned in the respective fields
139 */
140 UniformQuantizationInfo uniform() const
141 {
142 UniformQuantizationInfo uqinfo;
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100143 uqinfo.scale = _scale.empty() ? 0 : _scale[0];
144 uqinfo.offset = _offset.empty() ? 0 : _offset[0];
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100145
146 return uqinfo;
147 }
148
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100149private:
150 std::vector<float> _scale; /**< Vector containing scaling factors */
151 std::vector<int32_t> _offset; /**< Vector containing zero offsets */
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100152};
153
154/** Check whether two quantization info are equal.
155 *
156 * @param[in] lhs RHS quantization info.
157 * @param[in] rhs LHS quantization info.
158 *
159 * @return True if the given quantization info is the same.
160 */
161inline bool operator==(const QuantizationInfo &lhs, const QuantizationInfo &rhs)
162{
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100163 return (lhs.scale() == rhs.scale()) && (lhs.offset() == rhs.offset());
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100164}
165
166/** Check whether two quantization info are not equal.
167 *
168 * @param[in] lhs RHS quantization info.
169 * @param[in] rhs LHS quantization info.
170 *
171 * @return True if the given quantization info is the same.
172 */
173inline bool operator!=(const QuantizationInfo &lhs, const QuantizationInfo &rhs)
174{
175 return !(operator==(lhs, rhs));
176}
177
178/** Check whether two quantization info are equal.
179 *
180 * @param[in] lhs RHS quantization info.
181 * @param[in] rhs LHS quantization info.
182 *
183 * @return True if the given quantization info is the same.
184 */
185inline bool operator==(const UniformQuantizationInfo &lhs, const UniformQuantizationInfo &rhs)
186{
187 return (lhs.scale == rhs.scale) && (lhs.offset == rhs.offset);
188}
189
190/** Check whether two quantization info are not equal.
191 *
192 * @param[in] lhs RHS quantization info.
193 * @param[in] rhs LHS quantization info.
194 *
195 * @return True if the given quantization info is the same.
196 */
197inline bool operator!=(const UniformQuantizationInfo &lhs, const UniformQuantizationInfo &rhs)
198{
199 return !(operator==(lhs, rhs));
200}
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000201template <typename QUANTIZED_TYPE = uint8_t>
202struct Qasymm8QuantizationHelper
203{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100204 static_assert(std::is_same<QUANTIZED_TYPE, uint8_t>::value || std::is_same<QUANTIZED_TYPE, int8_t>::value,
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000205 "quantized type should be either uint8_t or int8_t.");
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100206
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000207 /** Quantize a value given a 8-bit asymmetric quantization scheme
208 *
Giorgio Arena433ea492021-05-26 15:32:50 +0100209 * @param[in] value Value to quantize
210 * @param[in] qinfo Quantization information to use for quantizing
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000211 *
212 * @return Quantized value
213 */
Giorgio Arena433ea492021-05-26 15:32:50 +0100214 static inline QUANTIZED_TYPE quantize(float value, const UniformQuantizationInfo &qinfo)
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000215 {
216 ARM_COMPUTE_ERROR_ON(qinfo.scale == 0);
Giorgio Arena433ea492021-05-26 15:32:50 +0100217 const int quantized = support::cpp11::lround(value / qinfo.scale) + qinfo.offset;
218 return static_cast<QUANTIZED_TYPE>(arm_compute::utility::clamp<decltype(quantized), QUANTIZED_TYPE>(quantized));
219 }
220
221 /** Quantize a value given a 8-bit asymmetric quantization scheme using a specific rounding policy
222 *
223 * @param[in] value Value to quantize
224 * @param[in] qinfo Quantization information to use for quantizing
225 * @param[in] rounding_policy Rounding policy to use
226 *
227 * @return Quantized value
228 */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100229 static inline QUANTIZED_TYPE
230 quantize(float value, const UniformQuantizationInfo &qinfo, RoundingPolicy rounding_policy)
Giorgio Arena433ea492021-05-26 15:32:50 +0100231 {
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100232 if (rounding_policy == RoundingPolicy::TO_NEAREST_UP)
Giorgio Arena433ea492021-05-26 15:32:50 +0100233 {
234 return quantize(value, qinfo);
235 }
236
237 ARM_COMPUTE_ERROR_ON(qinfo.scale == 0);
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000238 const int quantized = arm_compute::round(value / qinfo.scale, rounding_policy) + qinfo.offset;
239 return static_cast<QUANTIZED_TYPE>(arm_compute::utility::clamp<decltype(quantized), QUANTIZED_TYPE>(quantized));
240 }
241
242 /** Quantize a value given a 8-bit asymmetric quantization scheme
243 *
244 * @param[in] value Value to quantize
245 * @param[in] qinfo Quantization information to use for quantizing
246 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
247 *
248 * @return Quantized value
249 */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100250 static inline QUANTIZED_TYPE
251 quantize(float value, const QuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000252 {
253 const UniformQuantizationInfo uqinfo = qinfo.uniform();
254 ARM_COMPUTE_ERROR_ON(uqinfo.scale == 0);
255 const int quantized = arm_compute::round(value / uqinfo.scale, rounding_policy) + uqinfo.offset;
256 return static_cast<QUANTIZED_TYPE>(arm_compute::utility::clamp<decltype(quantized), QUANTIZED_TYPE>(quantized));
257 }
258
259 /** Dequantize a value given a 8-bit asymmetric quantization scheme
260 *
261 * @param[in] value Value to dequantize
262 * @param[in] qinfo Quantization information to use for dequantizing
263 *
264 * @return Dequantized value
265 */
266 static inline float dequantize(QUANTIZED_TYPE value, const UniformQuantizationInfo &qinfo)
267 {
268 return (static_cast<int>(value) - qinfo.offset) * qinfo.scale;
269 }
270
271 /** Dequantize a value given a 8-bit asymmetric quantization scheme
272 *
273 * @param[in] value Value to dequantize
274 * @param[in] qinfo Quantization information to use for dequantizing
275 *
276 * @return Dequantized value
277 */
278 static inline float dequantize(QUANTIZED_TYPE value, const QuantizationInfo &qinfo)
279 {
280 const UniformQuantizationInfo uqinfo = qinfo.uniform();
281 return (static_cast<int>(value) - uqinfo.offset) * uqinfo.scale;
282 }
283};
284
285/** Quantize a value given an unsigned 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100286 *
287 * @param[in] value Value to quantize
288 * @param[in] qinfo Quantization information to use for quantizing
289 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
290 *
291 * @return Quantized value
292 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000293template <typename INFO_TYPE>
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100294inline uint8_t
295quantize_qasymm8(float value, const INFO_TYPE &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100296{
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000297 return Qasymm8QuantizationHelper<uint8_t>::quantize(value, qinfo, rounding_policy);
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100298}
299
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000300/** Quantize a value given a signed 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100301 *
302 * @param[in] value Value to quantize
303 * @param[in] qinfo Quantization information to use for quantizing
304 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
305 *
306 * @return Quantized value
307 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000308template <typename INFO_TYPE>
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100309inline int8_t quantize_qasymm8_signed(float value,
310 const INFO_TYPE &qinfo,
311 RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100312{
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000313 return Qasymm8QuantizationHelper<int8_t>::quantize(value, qinfo, rounding_policy);
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100314}
315
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100316/** Quantize a value given a 8-bit symmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100317 *
318 * @param[in] value Value to quantize
319 * @param[in] qinfo Quantization information to use for quantizing
320 *
321 * @return Quantized value
322 */
323inline int8_t quantize_qsymm8(float value, const QuantizationInfo &qinfo)
324{
325 int quantized = arm_compute::round(value / qinfo.uniform().scale, RoundingPolicy::TO_NEAREST_UP);
326 quantized = std::max(-128, std::min(quantized, 127));
327 return quantized;
328}
329
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100330/** Quantize a value given a 8-bit symmetric per channel quantization scheme
331 *
332 * @param[in] value Value to quantize
333 * @param[in] qinfo Quantization information to use for quantizing
334 * @param[in] channel_id channel index into the scale vector of quantization info
335 *
336 * @return Quantized value
337 */
338inline int8_t quantize_qsymm8_per_channel(float value, const QuantizationInfo &qinfo, size_t channel_id = 0)
339{
340 int quantized = arm_compute::round(value / qinfo.scale()[channel_id], RoundingPolicy::TO_NEAREST_UP);
341 quantized = std::max(-128, std::min(quantized, 127));
342 return quantized;
343}
344
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000345/** Dequantize a value given an unsigned 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100346 *
347 * @param[in] value Value to dequantize
348 * @param[in] qinfo Quantization information to use for dequantizing
349 *
350 * @return Dequantized value
351 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000352template <typename INFO_TYPE>
353inline float dequantize_qasymm8(uint8_t value, const INFO_TYPE &qinfo)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100354{
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000355 return Qasymm8QuantizationHelper<uint8_t>::dequantize(value, qinfo);
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100356}
357
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000358/** Dequantize a value given a signed 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100359 *
360 * @param[in] value Value to dequantize
361 * @param[in] qinfo Quantization information to use for dequantizing
362 *
363 * @return Dequantized value
364 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000365template <typename INFO_TYPE>
366inline float dequantize_qasymm8_signed(int8_t value, const INFO_TYPE &qinfo)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100367{
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000368 return Qasymm8QuantizationHelper<int8_t>::dequantize(value, qinfo);
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100369}
370
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100371/** Dequantize a value given an 8-bit asymmetric quantization scheme
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100372 *
373 * @param[in] value Value to dequantize
374 * @param[in] scale Scale to use for dequantization
375 * @param[in] offset Zero-offset to use for dequantization
376 *
377 * @return Dequantized value
378 */
379inline float dequantize(uint8_t value, float scale, int32_t offset)
380{
381 return (static_cast<int>(value) - offset) * scale;
382}
383
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100384/** Dequantize a value given a 8-bit symmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100385 *
386 * @param[in] value Value to dequantize
387 * @param[in] qinfo Quantization information to use for dequantizing
388 *
389 * @return Dequantized value
390 */
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100391inline float dequantize_qsymm8(int8_t value, const UniformQuantizationInfo &qinfo)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100392{
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100393 return value * qinfo.scale;
394}
395
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100396/** Dequantize a value given a 8-bit symmetric quantization scheme
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100397 *
398 * @param[in] value Value to dequantize
399 * @param[in] scale Scale to use for dequantization
400 *
401 * @return Dequantized value
402 */
403inline float dequantize(int8_t value, float scale)
404{
405 return value * scale;
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100406}
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100407
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100408/** Dequantize a value given a 16-bit symmetric quantization scheme
Manuel Bottini10c53f12019-07-17 16:11:53 +0100409 *
410 * @param[in] value Value to dequantize
411 * @param[in] scale Scale to use for dequantization
412 *
413 * @return Dequantized value
414 */
415inline float dequantize(int16_t value, float scale)
416{
417 return value * scale;
418}
419
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100420/** Dequantize a value given a 16-bit asymmetric quantization scheme
421 *
422 * @param[in] value Value to dequantize
423 * @param[in] scale Scale to use for dequantization
424 * @param[in] offset Zero-offset to use for dequantization
425 *
426 * @return Dequantized value
427 */
428inline float dequantize(uint16_t value, float scale, int32_t offset)
429{
430 return (static_cast<int>(value) - offset) * scale;
431}
432
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100433/** Quantize a value given a 16-bit symmetric quantization scheme
434 *
435 * @param[in] value Value to quantize
436 * @param[in] qinfo Quantization information to use for quantizing
437 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
438 *
439 * @return Quantized value
440 */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100441inline int16_t quantize_qsymm16(float value,
442 const UniformQuantizationInfo &qinfo,
443 RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100444{
445 int quantized = arm_compute::round(value / qinfo.scale, rounding_policy);
446 quantized = arm_compute::utility::clamp<int, int16_t>(quantized);
447 return quantized;
448}
449
450/** Dequantize a value given a 16-bit symmetric quantization scheme
451 *
452 * @param[in] value Value to dequantize
453 * @param[in] qinfo Quantization information to use for dequantizing
454 *
455 * @return Dequantized value
456 */
457inline float dequantize_qsymm16(int16_t value, const UniformQuantizationInfo &qinfo)
458{
459 return value * qinfo.scale;
460}
461
462/** Quantize a value given a 16-bit symmetric quantization scheme
463 *
464 * @param[in] value Value to quantize
465 * @param[in] qinfo Quantization information to use for quantizing
466 *
467 * @return Quantized value
468 */
469inline int16_t quantize_qsymm16(float value, const QuantizationInfo &qinfo)
470{
471 return quantize_qsymm16(value, qinfo.uniform());
472}
473
474/** Dequantize a value given a 16-bit symmetric quantization scheme
475 *
476 * @param[in] value Value to dequantize
477 * @param[in] qinfo Quantization information to use for dequantizing
478 *
479 * @return Dequantized value
480 */
481inline float dequantize_qsymm16(int16_t value, const QuantizationInfo &qinfo)
482{
483 return dequantize_qsymm16(value, qinfo.uniform());
484}
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100485
486/** Quantize a value given a 16-bit asymmetric quantization scheme
487 *
488 * @param[in] value Value to quantize
489 * @param[in] qinfo Quantization information to use for quantizing
490 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
491 *
492 * @return Quantized value
493 */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100494inline uint16_t quantize_qasymm16(float value,
495 const UniformQuantizationInfo &qinfo,
496 RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100497{
498 int quantized = arm_compute::round(value / qinfo.scale, rounding_policy) + qinfo.offset;
499 quantized = arm_compute::utility::clamp<int, uint16_t>(quantized);
500 return quantized;
501}
502
503/** Dequantize a value given a 16-bit asymmetric quantization scheme
504 *
505 * @param[in] value Value to dequantize
506 * @param[in] qinfo Quantization information to use for dequantizing
507 *
508 * @return Dequantized value
509 */
510inline float dequantize_qasymm16(uint16_t value, const UniformQuantizationInfo &qinfo)
511{
512 return (static_cast<int>(value) - qinfo.offset) * qinfo.scale;
513}
514
515/** Quantize a value given a 16-bit asymmetric quantization scheme
516 *
517 * @param[in] value Value to quantize
518 * @param[in] qinfo Quantization information to use for quantizing
519 *
520 * @return Quantized value
521 */
522inline uint16_t quantize_qasymm16(float value, const QuantizationInfo &qinfo)
523{
524 return quantize_qasymm16(value, qinfo.uniform());
525}
526
527/** Dequantize a value given a 16-bit asymmetric quantization scheme
528 *
529 * @param[in] value Value to dequantize
530 * @param[in] qinfo Quantization information to use for dequantizing
531 *
532 * @return Dequantized value
533 */
534inline float dequantize_qasymm16(uint16_t value, const QuantizationInfo &qinfo)
535{
536 return dequantize_qasymm16(value, qinfo.uniform());
537}
Manuel Bottini4370cff2020-02-07 16:31:59 +0000538
539/*
540 * In case of requantization of a quantized input tensor to an output tensor with another quantization
541 * instead of applying dequantization and then a quantization functions, we just compute new scale and
542 * offset.
543 *
544 * Assuming:
545 * - q_i as input quantized value
546 * - q_o as output quantized value
547 * - z_i as input quantization offset value
548 * - z_o as output quantization offset value
549 * - s_i as input quantization scale value
550 * - s_o as output quantization scale value
551 * - z_n as new quantization offset value
552 * - s_n as new quantization scale value
553 *
554 * q_o = ( q_i - z_i ) * s_i / s_o + z_o
555 *
556 * We can rewrite the formula as:
557 *
558 * q_o = ( q_i * s_i / s_o ) - z_i * s_i / s_o + z_o
559 *
560 * q_o = q_i / s_n + z_n
561 *
562 * Where:
563 *
564 * s_n = s_o / s_i
565 *
566 * z_n = - z_i * s_i / s_o + z_o
567 *
568 */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100569inline UniformQuantizationInfo compute_requantization_scale_offset(const UniformQuantizationInfo &uqinfo_in,
570 const UniformQuantizationInfo &uqinfo_out)
Manuel Bottini4370cff2020-02-07 16:31:59 +0000571{
572 float scale_to_apply = uqinfo_out.scale;
573 int32_t offset_to_apply = uqinfo_out.offset;
574
575 scale_to_apply /= uqinfo_in.scale;
576 // In order to minimize flooring we convert the offset to a float,
577 // then compute the new offset in the float domain,
578 // finally we convert it back as int32_t
579 offset_to_apply -= static_cast<int32_t>(static_cast<float>(uqinfo_in.offset) * uqinfo_in.scale / uqinfo_out.scale);
580 return UniformQuantizationInfo(scale_to_apply, offset_to_apply);
581}
582
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100583} // namespace arm_compute
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000584#endif /* ARM_COMPUTE_QUANTIZATION_INFO_H */