blob: 52ef149e9ba2a0540520e020092e5d7149caca71 [file] [log] [blame]
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001/*
Manuel Bottini15e4d872020-04-01 12:35:36 +01002 * Copyright (c) 2019-2020 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
27#include "arm_compute/core/Rounding.h"
Manuel Bottini3689fcd2019-06-14 17:18:12 +010028#include "utils/misc/Utility.h"
Manuel Bottini15e4d872020-04-01 12:35:36 +010029#include "arm_compute/core/Error.h"
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010030
31#include <cstddef>
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +000032#include <type_traits>
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010033#include <vector>
34
35namespace arm_compute
36{
Michalis Spyrou8d4d1b82019-11-28 11:31:23 +000037using qasymm8_signed_t = int8_t; /**< 8 bit signed quantized asymmetric scalar value */
38using qasymm8_t = uint8_t; /**< 8 bit quantized asymmetric scalar value */
39using qsymm16_t = int16_t; /**< 16 bit quantized symmetric scalar value */
40using qasymm16_t = uint16_t; /**< 16 bit quantized asymmetric scalar value */
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010041
42/** Quantization info when assuming per layer quantization */
43struct UniformQuantizationInfo
44{
45 /** Default constructor */
46 UniformQuantizationInfo()
47 : scale(0.f), offset(0)
48 {
49 }
50 /** Constructor
51 *
52 * @param[in] scale Quantization scale
53 * @param[in] offset Quantization offset
54 */
55 UniformQuantizationInfo(float scale, int32_t offset)
56 : scale(scale), offset(offset)
57 {
58 }
59 /** Checks if the scale and offset are both zero */
60 bool empty() const
61 {
62 return (scale == 0) && (offset == 0);
63 }
64
65 float scale;
66 int32_t offset;
67};
68
69/** Quantization information */
Georgios Pinitas3d13af82019-06-04 13:04:16 +010070class QuantizationInfo
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010071{
Georgios Pinitas3d13af82019-06-04 13:04:16 +010072public:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010073 /** Default constructor */
74 QuantizationInfo() noexcept
Georgios Pinitas3d13af82019-06-04 13:04:16 +010075 : _scale(),
76 _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010077 {
78 }
79 /** Construct quantization info.
80 *
81 * @note Used for symmetric quantization
82 *
83 * @param[in] scale Scale.
84 */
85 QuantizationInfo(float scale)
Georgios Pinitas3d13af82019-06-04 13:04:16 +010086 : _scale(1, scale), _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010087 {
88 }
89 /** Construct quantization info.
90 *
91 * @note Used for asymmetric quantization
92 *
93 * @param[in] scale Scale.
94 * @param[in] offset Offset.
95 */
96 QuantizationInfo(float scale, int offset)
Georgios Pinitas3d13af82019-06-04 13:04:16 +010097 : _scale(1, scale), _offset(1, offset)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010098 {
99 }
100 /** Construct quantization info.
101 *
102 * @note Used for symmetric per channel quantization
103 *
104 * @param[in] scale Scale.
105 */
106 QuantizationInfo(std::vector<float> scale)
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100107 : _scale(scale), _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100108 {
109 }
Michalis Spyrou29a01c92019-08-22 11:44:04 +0100110 /** Construct quantization info.
111 *
112 * @note Used for asymmetric per channel quantization
113 *
114 * @param[in] scale Scale.
115 * @param[in] offset Offset.
116 */
117 QuantizationInfo(std::vector<float> scale, std::vector<int32_t> offset)
118 : _scale(scale), _offset(offset)
119 {
120 }
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100121 /** Scale vector accessor
122 *
123 * @return A reference to quantization scale metadata
124 */
125 const std::vector<float> &scale() const
126 {
127 return _scale;
128 }
129 /** Offset vector accessor
130 *
131 * @return A reference to quantization offset metadata
132 */
133 const std::vector<int32_t> &offset() const
134 {
135 return _offset;
136 }
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100137 /** Indicates whether this QuantizationInfo has valid settings or not
138 *
139 * @return True if the this has invalid settings.
140 */
141 bool empty() const
142 {
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100143 return _scale.empty() && _offset.empty();
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100144 }
145 /** Return per layer quantization info
146 *
147 * @return Uniform quantization information in case of empty information zero is returned in the respective fields
148 */
149 UniformQuantizationInfo uniform() const
150 {
151 UniformQuantizationInfo uqinfo;
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100152 uqinfo.scale = _scale.empty() ? 0 : _scale[0];
153 uqinfo.offset = _offset.empty() ? 0 : _offset[0];
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100154
155 return uqinfo;
156 }
157
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100158private:
159 std::vector<float> _scale; /**< Vector containing scaling factors */
160 std::vector<int32_t> _offset; /**< Vector containing zero offsets */
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100161};
162
163/** Check whether two quantization info are equal.
164 *
165 * @param[in] lhs RHS quantization info.
166 * @param[in] rhs LHS quantization info.
167 *
168 * @return True if the given quantization info is the same.
169 */
170inline bool operator==(const QuantizationInfo &lhs, const QuantizationInfo &rhs)
171{
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100172 return (lhs.scale() == rhs.scale()) && (lhs.offset() == rhs.offset());
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100173}
174
175/** Check whether two quantization info are not equal.
176 *
177 * @param[in] lhs RHS quantization info.
178 * @param[in] rhs LHS quantization info.
179 *
180 * @return True if the given quantization info is the same.
181 */
182inline bool operator!=(const QuantizationInfo &lhs, const QuantizationInfo &rhs)
183{
184 return !(operator==(lhs, rhs));
185}
186
187/** Check whether two quantization info are equal.
188 *
189 * @param[in] lhs RHS quantization info.
190 * @param[in] rhs LHS quantization info.
191 *
192 * @return True if the given quantization info is the same.
193 */
194inline bool operator==(const UniformQuantizationInfo &lhs, const UniformQuantizationInfo &rhs)
195{
196 return (lhs.scale == rhs.scale) && (lhs.offset == rhs.offset);
197}
198
199/** Check whether two quantization info are not equal.
200 *
201 * @param[in] lhs RHS quantization info.
202 * @param[in] rhs LHS quantization info.
203 *
204 * @return True if the given quantization info is the same.
205 */
206inline bool operator!=(const UniformQuantizationInfo &lhs, const UniformQuantizationInfo &rhs)
207{
208 return !(operator==(lhs, rhs));
209}
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000210template <typename QUANTIZED_TYPE = uint8_t>
211struct Qasymm8QuantizationHelper
212{
213 static_assert(std::is_same<QUANTIZED_TYPE, uint8_t>::value
214 || std::is_same<QUANTIZED_TYPE, int8_t>::value,
215 "quantized type should be either uint8_t or int8_t.");
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100216
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000217 /** Quantize a value given a 8-bit asymmetric quantization scheme
218 *
219 * @param[in] value Value to quantize
220 * @param[in] qinfo Quantization information to use for quantizing
221 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
222 *
223 * @return Quantized value
224 */
225 static inline QUANTIZED_TYPE quantize(float value, const UniformQuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
226 {
227 ARM_COMPUTE_ERROR_ON(qinfo.scale == 0);
228 const int quantized = arm_compute::round(value / qinfo.scale, rounding_policy) + qinfo.offset;
229 return static_cast<QUANTIZED_TYPE>(arm_compute::utility::clamp<decltype(quantized), QUANTIZED_TYPE>(quantized));
230 }
231
232 /** Quantize a value given a 8-bit asymmetric quantization scheme
233 *
234 * @param[in] value Value to quantize
235 * @param[in] qinfo Quantization information to use for quantizing
236 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
237 *
238 * @return Quantized value
239 */
240 static inline QUANTIZED_TYPE quantize(float value, const QuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
241 {
242 const UniformQuantizationInfo uqinfo = qinfo.uniform();
243 ARM_COMPUTE_ERROR_ON(uqinfo.scale == 0);
244 const int quantized = arm_compute::round(value / uqinfo.scale, rounding_policy) + uqinfo.offset;
245 return static_cast<QUANTIZED_TYPE>(arm_compute::utility::clamp<decltype(quantized), QUANTIZED_TYPE>(quantized));
246 }
247
248 /** Dequantize a value given a 8-bit asymmetric quantization scheme
249 *
250 * @param[in] value Value to dequantize
251 * @param[in] qinfo Quantization information to use for dequantizing
252 *
253 * @return Dequantized value
254 */
255 static inline float dequantize(QUANTIZED_TYPE value, const UniformQuantizationInfo &qinfo)
256 {
257 return (static_cast<int>(value) - qinfo.offset) * qinfo.scale;
258 }
259
260 /** Dequantize a value given a 8-bit asymmetric quantization scheme
261 *
262 * @param[in] value Value to dequantize
263 * @param[in] qinfo Quantization information to use for dequantizing
264 *
265 * @return Dequantized value
266 */
267 static inline float dequantize(QUANTIZED_TYPE value, const QuantizationInfo &qinfo)
268 {
269 const UniformQuantizationInfo uqinfo = qinfo.uniform();
270 return (static_cast<int>(value) - uqinfo.offset) * uqinfo.scale;
271 }
272};
273
274/** Quantize a value given an unsigned 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100275 *
276 * @param[in] value Value to quantize
277 * @param[in] qinfo Quantization information to use for quantizing
278 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
279 *
280 * @return Quantized value
281 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000282template <typename INFO_TYPE>
283inline uint8_t quantize_qasymm8(float value, const INFO_TYPE &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100284{
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000285 return Qasymm8QuantizationHelper<uint8_t>::quantize(value, qinfo, rounding_policy);
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100286}
287
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000288/** Quantize a value given a signed 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100289 *
290 * @param[in] value Value to quantize
291 * @param[in] qinfo Quantization information to use for quantizing
292 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
293 *
294 * @return Quantized value
295 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000296template <typename INFO_TYPE>
297inline 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 +0100298{
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000299 return Qasymm8QuantizationHelper<int8_t>::quantize(value, qinfo, rounding_policy);
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100300}
301
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100302/** Quantize a value given a 8-bit symmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100303 *
304 * @param[in] value Value to quantize
305 * @param[in] qinfo Quantization information to use for quantizing
306 *
307 * @return Quantized value
308 */
309inline int8_t quantize_qsymm8(float value, const QuantizationInfo &qinfo)
310{
311 int quantized = arm_compute::round(value / qinfo.uniform().scale, RoundingPolicy::TO_NEAREST_UP);
312 quantized = std::max(-128, std::min(quantized, 127));
313 return quantized;
314}
315
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100316/** Quantize a value given a 8-bit symmetric per channel quantization scheme
317 *
318 * @param[in] value Value to quantize
319 * @param[in] qinfo Quantization information to use for quantizing
320 * @param[in] channel_id channel index into the scale vector of quantization info
321 *
322 * @return Quantized value
323 */
324inline int8_t quantize_qsymm8_per_channel(float value, const QuantizationInfo &qinfo, size_t channel_id = 0)
325{
326 int quantized = arm_compute::round(value / qinfo.scale()[channel_id], RoundingPolicy::TO_NEAREST_UP);
327 quantized = std::max(-128, std::min(quantized, 127));
328 return quantized;
329}
330
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000331/** Dequantize a value given an unsigned 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100332 *
333 * @param[in] value Value to dequantize
334 * @param[in] qinfo Quantization information to use for dequantizing
335 *
336 * @return Dequantized value
337 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000338template <typename INFO_TYPE>
339inline float dequantize_qasymm8(uint8_t value, const INFO_TYPE &qinfo)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100340{
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000341 return Qasymm8QuantizationHelper<uint8_t>::dequantize(value, qinfo);
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100342}
343
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000344/** Dequantize a value given a signed 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100345 *
346 * @param[in] value Value to dequantize
347 * @param[in] qinfo Quantization information to use for dequantizing
348 *
349 * @return Dequantized value
350 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000351template <typename INFO_TYPE>
352inline float dequantize_qasymm8_signed(int8_t value, const INFO_TYPE &qinfo)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100353{
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000354 return Qasymm8QuantizationHelper<int8_t>::dequantize(value, qinfo);
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100355}
356
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100357/** Dequantize a value given an 8-bit asymmetric quantization scheme
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100358 *
359 * @param[in] value Value to dequantize
360 * @param[in] scale Scale to use for dequantization
361 * @param[in] offset Zero-offset to use for dequantization
362 *
363 * @return Dequantized value
364 */
365inline float dequantize(uint8_t value, float scale, int32_t offset)
366{
367 return (static_cast<int>(value) - offset) * scale;
368}
369
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100370/** Dequantize a value given a 8-bit symmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100371 *
372 * @param[in] value Value to dequantize
373 * @param[in] qinfo Quantization information to use for dequantizing
374 *
375 * @return Dequantized value
376 */
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100377inline float dequantize_qsymm8(int8_t value, const UniformQuantizationInfo &qinfo)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100378{
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100379 return value * qinfo.scale;
380}
381
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100382/** Dequantize a value given a 8-bit symmetric quantization scheme
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100383 *
384 * @param[in] value Value to dequantize
385 * @param[in] scale Scale to use for dequantization
386 *
387 * @return Dequantized value
388 */
389inline float dequantize(int8_t value, float scale)
390{
391 return value * scale;
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100392}
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100393
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100394/** Dequantize a value given a 16-bit symmetric quantization scheme
Manuel Bottini10c53f12019-07-17 16:11:53 +0100395 *
396 * @param[in] value Value to dequantize
397 * @param[in] scale Scale to use for dequantization
398 *
399 * @return Dequantized value
400 */
401inline float dequantize(int16_t value, float scale)
402{
403 return value * scale;
404}
405
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100406/** Dequantize a value given a 16-bit asymmetric quantization scheme
407 *
408 * @param[in] value Value to dequantize
409 * @param[in] scale Scale to use for dequantization
410 * @param[in] offset Zero-offset to use for dequantization
411 *
412 * @return Dequantized value
413 */
414inline float dequantize(uint16_t value, float scale, int32_t offset)
415{
416 return (static_cast<int>(value) - offset) * scale;
417}
418
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100419/** Quantize a value given a 16-bit symmetric quantization scheme
420 *
421 * @param[in] value Value to quantize
422 * @param[in] qinfo Quantization information to use for quantizing
423 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
424 *
425 * @return Quantized value
426 */
427inline int16_t quantize_qsymm16(float value, const UniformQuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
428{
429 int quantized = arm_compute::round(value / qinfo.scale, rounding_policy);
430 quantized = arm_compute::utility::clamp<int, int16_t>(quantized);
431 return quantized;
432}
433
434/** Dequantize a value given a 16-bit symmetric quantization scheme
435 *
436 * @param[in] value Value to dequantize
437 * @param[in] qinfo Quantization information to use for dequantizing
438 *
439 * @return Dequantized value
440 */
441inline float dequantize_qsymm16(int16_t value, const UniformQuantizationInfo &qinfo)
442{
443 return value * qinfo.scale;
444}
445
446/** Quantize a value given a 16-bit symmetric quantization scheme
447 *
448 * @param[in] value Value to quantize
449 * @param[in] qinfo Quantization information to use for quantizing
450 *
451 * @return Quantized value
452 */
453inline int16_t quantize_qsymm16(float value, const QuantizationInfo &qinfo)
454{
455 return quantize_qsymm16(value, qinfo.uniform());
456}
457
458/** Dequantize a value given a 16-bit symmetric quantization scheme
459 *
460 * @param[in] value Value to dequantize
461 * @param[in] qinfo Quantization information to use for dequantizing
462 *
463 * @return Dequantized value
464 */
465inline float dequantize_qsymm16(int16_t value, const QuantizationInfo &qinfo)
466{
467 return dequantize_qsymm16(value, qinfo.uniform());
468}
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100469
470/** Quantize a value given a 16-bit asymmetric quantization scheme
471 *
472 * @param[in] value Value to quantize
473 * @param[in] qinfo Quantization information to use for quantizing
474 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
475 *
476 * @return Quantized value
477 */
478inline uint16_t quantize_qasymm16(float value, const UniformQuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
479{
480 int quantized = arm_compute::round(value / qinfo.scale, rounding_policy) + qinfo.offset;
481 quantized = arm_compute::utility::clamp<int, uint16_t>(quantized);
482 return quantized;
483}
484
485/** Dequantize a value given a 16-bit asymmetric quantization scheme
486 *
487 * @param[in] value Value to dequantize
488 * @param[in] qinfo Quantization information to use for dequantizing
489 *
490 * @return Dequantized value
491 */
492inline float dequantize_qasymm16(uint16_t value, const UniformQuantizationInfo &qinfo)
493{
494 return (static_cast<int>(value) - qinfo.offset) * qinfo.scale;
495}
496
497/** Quantize a value given a 16-bit asymmetric quantization scheme
498 *
499 * @param[in] value Value to quantize
500 * @param[in] qinfo Quantization information to use for quantizing
501 *
502 * @return Quantized value
503 */
504inline uint16_t quantize_qasymm16(float value, const QuantizationInfo &qinfo)
505{
506 return quantize_qasymm16(value, qinfo.uniform());
507}
508
509/** Dequantize a value given a 16-bit asymmetric quantization scheme
510 *
511 * @param[in] value Value to dequantize
512 * @param[in] qinfo Quantization information to use for dequantizing
513 *
514 * @return Dequantized value
515 */
516inline float dequantize_qasymm16(uint16_t value, const QuantizationInfo &qinfo)
517{
518 return dequantize_qasymm16(value, qinfo.uniform());
519}
Manuel Bottini4370cff2020-02-07 16:31:59 +0000520
521/*
522 * In case of requantization of a quantized input tensor to an output tensor with another quantization
523 * instead of applying dequantization and then a quantization functions, we just compute new scale and
524 * offset.
525 *
526 * Assuming:
527 * - q_i as input quantized value
528 * - q_o as output quantized value
529 * - z_i as input quantization offset value
530 * - z_o as output quantization offset value
531 * - s_i as input quantization scale value
532 * - s_o as output quantization scale value
533 * - z_n as new quantization offset value
534 * - s_n as new quantization scale value
535 *
536 * q_o = ( q_i - z_i ) * s_i / s_o + z_o
537 *
538 * We can rewrite the formula as:
539 *
540 * q_o = ( q_i * s_i / s_o ) - z_i * s_i / s_o + z_o
541 *
542 * q_o = q_i / s_n + z_n
543 *
544 * Where:
545 *
546 * s_n = s_o / s_i
547 *
548 * z_n = - z_i * s_i / s_o + z_o
549 *
550 */
551inline UniformQuantizationInfo compute_requantization_scale_offset(const UniformQuantizationInfo &uqinfo_in, const UniformQuantizationInfo &uqinfo_out)
552{
553 float scale_to_apply = uqinfo_out.scale;
554 int32_t offset_to_apply = uqinfo_out.offset;
555
556 scale_to_apply /= uqinfo_in.scale;
557 // In order to minimize flooring we convert the offset to a float,
558 // then compute the new offset in the float domain,
559 // finally we convert it back as int32_t
560 offset_to_apply -= static_cast<int32_t>(static_cast<float>(uqinfo_in.offset) * uqinfo_in.scale / uqinfo_out.scale);
561 return UniformQuantizationInfo(scale_to_apply, offset_to_apply);
562}
563
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100564} // namespace arm_compute
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000565#endif /* ARM_COMPUTE_QUANTIZATION_INFO_H */