xref: /aosp_15_r20/external/ComputeLibrary/arm_compute/core/QuantizationInfo.h (revision c217d954acce2dbc11938adb493fc0abd69584f3)
1 /*
2  * Copyright (c) 2019-2022 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/Error.h"
28 #include "arm_compute/core/Rounding.h"
29 #include "support/ToolchainSupport.h"
30 #include "utils/misc/Utility.h"
31 
32 #include <cstddef>
33 #include <type_traits>
34 #include <vector>
35 
36 namespace arm_compute
37 {
38 using qasymm8_signed_t = int8_t;   /**< 8 bit signed quantized asymmetric scalar value */
39 using qasymm8_t        = uint8_t;  /**< 8 bit quantized asymmetric scalar value */
40 using qsymm16_t        = int16_t;  /**< 16 bit quantized symmetric scalar value */
41 using qasymm16_t       = uint16_t; /**< 16 bit quantized asymmetric scalar value */
42 
43 /** Quantization info when assuming per layer quantization */
44 struct UniformQuantizationInfo
45 {
46     /** Default constructor */
UniformQuantizationInfoUniformQuantizationInfo47     UniformQuantizationInfo()
48         : scale(0.f), offset(0)
49     {
50     }
51     /** Constructor
52      *
53      * @param[in] scale  Quantization scale
54      * @param[in] offset Quantization offset
55      */
UniformQuantizationInfoUniformQuantizationInfo56     UniformQuantizationInfo(float scale, int32_t offset)
57         : scale(scale), offset(offset)
58     {
59     }
60     /** Checks if the scale and offset are both zero */
emptyUniformQuantizationInfo61     bool empty() const
62     {
63         return (scale == 0) && (offset == 0);
64     }
65 
66     float   scale;
67     int32_t offset;
68 };
69 
70 /** Quantization information */
71 class QuantizationInfo
72 {
73 public:
74     /** Default constructor */
QuantizationInfo()75     QuantizationInfo() noexcept
76         : _scale(),
77           _offset()
78     {
79     }
80     /** Construct quantization info.
81      *
82      * @note Used for symmetric quantization
83      *
84      * @param[in] scale Scale.
85      */
QuantizationInfo(float scale)86     QuantizationInfo(float scale)
87         : _scale(1, scale), _offset()
88     {
89     }
90     /** Construct quantization info.
91      *
92      * @note Used for asymmetric quantization
93      *
94      * @param[in] scale  Scale.
95      * @param[in] offset Offset.
96      */
QuantizationInfo(float scale,int offset)97     QuantizationInfo(float scale, int offset)
98         : _scale(1, scale), _offset(1, offset)
99     {
100     }
101     /** Construct quantization info.
102      *
103      * @note Used for symmetric per channel quantization
104      *
105      * @param[in] scale Scale.
106      */
QuantizationInfo(std::vector<float> scale)107     QuantizationInfo(std::vector<float> scale)
108         : _scale(scale), _offset()
109     {
110     }
111     /** Construct quantization info.
112      *
113      * @note Used for asymmetric per channel quantization
114      *
115      * @param[in] scale  Scale.
116      * @param[in] offset Offset.
117      */
QuantizationInfo(std::vector<float> scale,std::vector<int32_t> offset)118     QuantizationInfo(std::vector<float> scale, std::vector<int32_t> offset)
119         : _scale(scale), _offset(offset)
120     {
121     }
122     /** Scale vector accessor
123      *
124      * @return A reference to quantization scale metadata
125      */
scale()126     const std::vector<float> &scale() const
127     {
128         return _scale;
129     }
130     /** Offset vector accessor
131      *
132      * @return A reference to quantization offset metadata
133      */
offset()134     const std::vector<int32_t> &offset() const
135     {
136         return _offset;
137     }
138     /** Indicates whether this QuantizationInfo has valid settings or not
139      *
140      * @return True if the this has invalid settings.
141      */
empty()142     bool empty() const
143     {
144         return _scale.empty() && _offset.empty();
145     }
146     /** Return per layer quantization info
147      *
148      * @return Uniform quantization information in case of empty information zero is returned in the respective fields
149      */
uniform()150     UniformQuantizationInfo uniform() const
151     {
152         UniformQuantizationInfo uqinfo;
153         uqinfo.scale  = _scale.empty() ? 0 : _scale[0];
154         uqinfo.offset = _offset.empty() ? 0 : _offset[0];
155 
156         return uqinfo;
157     }
158 
159 private:
160     std::vector<float>   _scale;  /**< Vector containing scaling factors */
161     std::vector<int32_t> _offset; /**< Vector containing zero offsets */
162 };
163 
164 /** Check whether two quantization info are equal.
165  *
166  * @param[in] lhs RHS quantization info.
167  * @param[in] rhs LHS quantization info.
168  *
169  * @return True if the given quantization info is the same.
170  */
171 inline bool operator==(const QuantizationInfo &lhs, const QuantizationInfo &rhs)
172 {
173     return (lhs.scale() == rhs.scale()) && (lhs.offset() == rhs.offset());
174 }
175 
176 /** Check whether two quantization info are not equal.
177  *
178  * @param[in] lhs RHS quantization info.
179  * @param[in] rhs LHS quantization info.
180  *
181  * @return True if the given quantization info is the same.
182  */
183 inline bool operator!=(const QuantizationInfo &lhs, const QuantizationInfo &rhs)
184 {
185     return !(operator==(lhs, rhs));
186 }
187 
188 /** Check whether two quantization info are equal.
189  *
190  * @param[in] lhs RHS quantization info.
191  * @param[in] rhs LHS quantization info.
192  *
193  * @return True if the given quantization info is the same.
194  */
195 inline bool operator==(const UniformQuantizationInfo &lhs, const UniformQuantizationInfo &rhs)
196 {
197     return (lhs.scale == rhs.scale) && (lhs.offset == rhs.offset);
198 }
199 
200 /** Check whether two quantization info are not equal.
201  *
202  * @param[in] lhs RHS quantization info.
203  * @param[in] rhs LHS quantization info.
204  *
205  * @return True if the given quantization info is the same.
206  */
207 inline bool operator!=(const UniformQuantizationInfo &lhs, const UniformQuantizationInfo &rhs)
208 {
209     return !(operator==(lhs, rhs));
210 }
211 template <typename QUANTIZED_TYPE = uint8_t>
212 struct Qasymm8QuantizationHelper
213 {
214     static_assert(std::is_same<QUANTIZED_TYPE, uint8_t>::value
215                   || std::is_same<QUANTIZED_TYPE, int8_t>::value,
216                   "quantized type should be either uint8_t or int8_t.");
217 
218     /** Quantize a value given a 8-bit asymmetric quantization scheme
219      *
220      * @param[in] value Value to quantize
221      * @param[in] qinfo Quantization information to use for quantizing
222      *
223      * @return Quantized value
224      */
quantizeQasymm8QuantizationHelper225     static inline QUANTIZED_TYPE quantize(float value, const UniformQuantizationInfo &qinfo)
226     {
227         ARM_COMPUTE_ERROR_ON(qinfo.scale == 0);
228         const int quantized = support::cpp11::lround(value / qinfo.scale) + 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 using a specific rounding policy
233      *
234      * @param[in] value           Value to quantize
235      * @param[in] qinfo           Quantization information to use for quantizing
236      * @param[in] rounding_policy Rounding policy to use
237      *
238      * @return Quantized value
239      */
quantizeQasymm8QuantizationHelper240     static inline QUANTIZED_TYPE quantize(float value, const UniformQuantizationInfo &qinfo, RoundingPolicy rounding_policy)
241     {
242         if(rounding_policy == RoundingPolicy::TO_NEAREST_UP)
243         {
244             return quantize(value, qinfo);
245         }
246 
247         ARM_COMPUTE_ERROR_ON(qinfo.scale == 0);
248         const int quantized = arm_compute::round(value / qinfo.scale, rounding_policy) + qinfo.offset;
249         return static_cast<QUANTIZED_TYPE>(arm_compute::utility::clamp<decltype(quantized), QUANTIZED_TYPE>(quantized));
250     }
251 
252     /** Quantize a value given a 8-bit asymmetric quantization scheme
253      *
254      * @param[in] value           Value to quantize
255      * @param[in] qinfo           Quantization information to use for quantizing
256      * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
257      *
258      * @return Quantized value
259      */
260     static inline QUANTIZED_TYPE quantize(float value, const QuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
261     {
262         const UniformQuantizationInfo uqinfo = qinfo.uniform();
263         ARM_COMPUTE_ERROR_ON(uqinfo.scale == 0);
264         const int quantized = arm_compute::round(value / uqinfo.scale, rounding_policy) + uqinfo.offset;
265         return static_cast<QUANTIZED_TYPE>(arm_compute::utility::clamp<decltype(quantized), QUANTIZED_TYPE>(quantized));
266     }
267 
268     /** Dequantize a value given a 8-bit asymmetric quantization scheme
269      *
270      * @param[in] value Value to dequantize
271      * @param[in] qinfo Quantization information to use for dequantizing
272      *
273      * @return Dequantized value
274      */
dequantizeQasymm8QuantizationHelper275     static inline float dequantize(QUANTIZED_TYPE value, const UniformQuantizationInfo &qinfo)
276     {
277         return (static_cast<int>(value) - qinfo.offset) * qinfo.scale;
278     }
279 
280     /** Dequantize a value given a 8-bit asymmetric quantization scheme
281      *
282      * @param[in] value Value to dequantize
283      * @param[in] qinfo Quantization information to use for dequantizing
284      *
285      * @return Dequantized value
286      */
dequantizeQasymm8QuantizationHelper287     static inline float dequantize(QUANTIZED_TYPE value, const QuantizationInfo &qinfo)
288     {
289         const UniformQuantizationInfo uqinfo = qinfo.uniform();
290         return (static_cast<int>(value) - uqinfo.offset) * uqinfo.scale;
291     }
292 };
293 
294 /** Quantize a value given an unsigned 8-bit asymmetric quantization scheme
295  *
296  * @param[in] value           Value to quantize
297  * @param[in] qinfo           Quantization information to use for quantizing
298  * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
299  *
300  * @return Quantized value
301  */
302 template <typename INFO_TYPE>
303 inline uint8_t quantize_qasymm8(float value, const INFO_TYPE &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
304 {
305     return Qasymm8QuantizationHelper<uint8_t>::quantize(value, qinfo, rounding_policy);
306 }
307 
308 /** Quantize a value given a signed 8-bit asymmetric quantization scheme
309  *
310  * @param[in] value           Value to quantize
311  * @param[in] qinfo           Quantization information to use for quantizing
312  * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
313  *
314  * @return Quantized value
315  */
316 template <typename INFO_TYPE>
317 inline int8_t quantize_qasymm8_signed(float value, const INFO_TYPE &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
318 {
319     return Qasymm8QuantizationHelper<int8_t>::quantize(value, qinfo, rounding_policy);
320 }
321 
322 /** Quantize a value given a 8-bit symmetric quantization scheme
323  *
324  * @param[in] value Value to quantize
325  * @param[in] qinfo Quantization information to use for quantizing
326  *
327  * @return Quantized value
328  */
quantize_qsymm8(float value,const QuantizationInfo & qinfo)329 inline int8_t quantize_qsymm8(float value, const QuantizationInfo &qinfo)
330 {
331     int quantized = arm_compute::round(value / qinfo.uniform().scale, RoundingPolicy::TO_NEAREST_UP);
332     quantized     = std::max(-128, std::min(quantized, 127));
333     return quantized;
334 }
335 
336 /** Quantize a value given a 8-bit symmetric per channel quantization scheme
337  *
338  * @param[in] value      Value to quantize
339  * @param[in] qinfo      Quantization information to use for quantizing
340  * @param[in] channel_id channel index into the scale vector of quantization info
341  *
342  * @return Quantized value
343  */
344 inline int8_t quantize_qsymm8_per_channel(float value, const QuantizationInfo &qinfo, size_t channel_id = 0)
345 {
346     int quantized = arm_compute::round(value / qinfo.scale()[channel_id], RoundingPolicy::TO_NEAREST_UP);
347     quantized     = std::max(-128, std::min(quantized, 127));
348     return quantized;
349 }
350 
351 /** Dequantize a value given an unsigned 8-bit asymmetric quantization scheme
352  *
353  * @param[in] value Value to dequantize
354  * @param[in] qinfo Quantization information to use for dequantizing
355  *
356  * @return Dequantized value
357  */
358 template <typename INFO_TYPE>
dequantize_qasymm8(uint8_t value,const INFO_TYPE & qinfo)359 inline float dequantize_qasymm8(uint8_t value, const INFO_TYPE &qinfo)
360 {
361     return Qasymm8QuantizationHelper<uint8_t>::dequantize(value, qinfo);
362 }
363 
364 /** Dequantize a value given a signed 8-bit asymmetric quantization scheme
365  *
366  * @param[in] value Value to dequantize
367  * @param[in] qinfo Quantization information to use for dequantizing
368  *
369  * @return Dequantized value
370  */
371 template <typename INFO_TYPE>
dequantize_qasymm8_signed(int8_t value,const INFO_TYPE & qinfo)372 inline float dequantize_qasymm8_signed(int8_t value, const INFO_TYPE &qinfo)
373 {
374     return Qasymm8QuantizationHelper<int8_t>::dequantize(value, qinfo);
375 }
376 
377 /** Dequantize a value given an 8-bit asymmetric quantization scheme
378  *
379  * @param[in] value  Value to dequantize
380  * @param[in] scale  Scale to use for dequantization
381  * @param[in] offset Zero-offset to use for dequantization
382  *
383  * @return Dequantized value
384  */
dequantize(uint8_t value,float scale,int32_t offset)385 inline float dequantize(uint8_t value, float scale, int32_t offset)
386 {
387     return (static_cast<int>(value) - offset) * scale;
388 }
389 
390 /** Dequantize a value given a 8-bit symmetric quantization scheme
391  *
392  * @param[in] value Value to dequantize
393  * @param[in] qinfo Quantization information to use for dequantizing
394  *
395  * @return Dequantized value
396  */
dequantize_qsymm8(int8_t value,const UniformQuantizationInfo & qinfo)397 inline float dequantize_qsymm8(int8_t value, const UniformQuantizationInfo &qinfo)
398 {
399     return value * qinfo.scale;
400 }
401 
qasymm8_hard_swish(qasymm8_t in,const UniformQuantizationInfo & qi_in,const UniformQuantizationInfo & qi_out)402 inline qasymm8_t qasymm8_hard_swish(qasymm8_t                      in,
403                                     const UniformQuantizationInfo &qi_in,
404                                     const UniformQuantizationInfo &qi_out)
405 {
406     float tmp_f         = dequantize_qasymm8(in, qi_in);
407     tmp_f               = tmp_f * ((std::min(std::max((tmp_f + 3), 0.0f), 6.0f)) * 0.166666667f);
408     const qasymm8_t tmp = quantize_qasymm8(tmp_f, qi_out);
409     return tmp;
410 }
411 
qasymm8_signed_hard_swish(qasymm8_signed_t in,const UniformQuantizationInfo & qi_in,const UniformQuantizationInfo & qi_out)412 inline qasymm8_signed_t qasymm8_signed_hard_swish(qasymm8_signed_t               in,
413                                                   const UniformQuantizationInfo &qi_in,
414                                                   const UniformQuantizationInfo &qi_out)
415 {
416     float tmp_f         = dequantize_qasymm8_signed(in, qi_in);
417     tmp_f               = tmp_f * ((std::min(std::max((tmp_f + 3), 0.0f), 6.0f)) * 0.166666667f);
418     const qasymm8_t tmp = quantize_qasymm8_signed(tmp_f, qi_out);
419     return tmp;
420 }
421 
qasymm8_leaky_relu(qasymm8_t in,const UniformQuantizationInfo & qi_in,const UniformQuantizationInfo & qi_out,float alpha)422 inline qasymm8_t qasymm8_leaky_relu(qasymm8_t                      in,
423                                     const UniformQuantizationInfo &qi_in,
424                                     const UniformQuantizationInfo &qi_out,
425                                     float                          alpha)
426 {
427     float tmp_f         = dequantize_qasymm8(in, qi_in);
428     tmp_f               = tmp_f > 0 ? tmp_f : tmp_f * alpha;
429     const qasymm8_t tmp = quantize_qasymm8(tmp_f, qi_out);
430     return tmp;
431 }
432 
qasymm8_logistic(qasymm8_t in,const UniformQuantizationInfo & qi_in,const UniformQuantizationInfo & qi_out)433 inline qasymm8_t qasymm8_logistic(qasymm8_t                      in,
434                                   const UniformQuantizationInfo &qi_in,
435                                   const UniformQuantizationInfo &qi_out)
436 {
437     float tmp_f         = dequantize_qasymm8(in, qi_in);
438     tmp_f               = 1.f / (1.f + std::exp(-tmp_f));
439     const qasymm8_t tmp = quantize_qasymm8(tmp_f, qi_out);
440     return tmp;
441 }
442 
qasymm8_signed_logistic(qasymm8_signed_t in,const UniformQuantizationInfo & qi_in,const UniformQuantizationInfo & qi_out)443 inline qasymm8_signed_t qasymm8_signed_logistic(qasymm8_signed_t               in,
444                                                 const UniformQuantizationInfo &qi_in,
445                                                 const UniformQuantizationInfo &qi_out)
446 {
447     float tmp_f                = dequantize_qasymm8_signed(in, qi_in);
448     tmp_f                      = 1.f / (1.f + std::exp(-tmp_f));
449     const qasymm8_signed_t tmp = quantize_qasymm8_signed(tmp_f, qi_out);
450     return tmp;
451 }
452 
453 /** Dequantize a value given a 8-bit symmetric quantization scheme
454  *
455  * @param[in] value Value to dequantize
456  * @param[in] scale Scale to use for dequantization
457  *
458  * @return Dequantized value
459  */
dequantize(int8_t value,float scale)460 inline float dequantize(int8_t value, float scale)
461 {
462     return value * scale;
463 }
464 
465 /** Dequantize a value given a 16-bit symmetric quantization scheme
466  *
467  * @param[in] value Value to dequantize
468  * @param[in] scale Scale to use for dequantization
469  *
470  * @return Dequantized value
471  */
dequantize(int16_t value,float scale)472 inline float dequantize(int16_t value, float scale)
473 {
474     return value * scale;
475 }
476 
477 /** Dequantize a value given a 16-bit asymmetric quantization scheme
478  *
479  * @param[in] value  Value to dequantize
480  * @param[in] scale  Scale to use for dequantization
481  * @param[in] offset Zero-offset to use for dequantization
482  *
483  * @return Dequantized value
484  */
dequantize(uint16_t value,float scale,int32_t offset)485 inline float dequantize(uint16_t value, float scale, int32_t offset)
486 {
487     return (static_cast<int>(value) - offset) * scale;
488 }
489 
490 /** Quantize a value given a 16-bit symmetric quantization scheme
491  *
492  * @param[in] value           Value to quantize
493  * @param[in] qinfo           Quantization information to use for quantizing
494  * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
495  *
496  * @return Quantized value
497  */
498 inline int16_t quantize_qsymm16(float value, const UniformQuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
499 {
500     int quantized = arm_compute::round(value / qinfo.scale, rounding_policy);
501     quantized     = arm_compute::utility::clamp<int, int16_t>(quantized);
502     return quantized;
503 }
504 
505 /** Dequantize a value given a 16-bit symmetric quantization scheme
506  *
507  * @param[in] value Value to dequantize
508  * @param[in] qinfo Quantization information to use for dequantizing
509  *
510  * @return Dequantized value
511  */
dequantize_qsymm16(int16_t value,const UniformQuantizationInfo & qinfo)512 inline float dequantize_qsymm16(int16_t value, const UniformQuantizationInfo &qinfo)
513 {
514     return value * qinfo.scale;
515 }
516 
517 /** Quantize a value given a 16-bit symmetric quantization scheme
518  *
519  * @param[in] value Value to quantize
520  * @param[in] qinfo Quantization information to use for quantizing
521  *
522  * @return Quantized value
523  */
quantize_qsymm16(float value,const QuantizationInfo & qinfo)524 inline int16_t quantize_qsymm16(float value, const QuantizationInfo &qinfo)
525 {
526     return quantize_qsymm16(value, qinfo.uniform());
527 }
528 
529 /** Dequantize a value given a 16-bit symmetric quantization scheme
530  *
531  * @param[in] value Value to dequantize
532  * @param[in] qinfo Quantization information to use for dequantizing
533  *
534  * @return Dequantized value
535  */
dequantize_qsymm16(int16_t value,const QuantizationInfo & qinfo)536 inline float dequantize_qsymm16(int16_t value, const QuantizationInfo &qinfo)
537 {
538     return dequantize_qsymm16(value, qinfo.uniform());
539 }
540 
541 /** Quantize a value given a 16-bit asymmetric quantization scheme
542  *
543  * @param[in] value           Value to quantize
544  * @param[in] qinfo           Quantization information to use for quantizing
545  * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
546  *
547  * @return Quantized value
548  */
549 inline uint16_t quantize_qasymm16(float value, const UniformQuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
550 {
551     int quantized = arm_compute::round(value / qinfo.scale, rounding_policy) + qinfo.offset;
552     quantized     = arm_compute::utility::clamp<int, uint16_t>(quantized);
553     return quantized;
554 }
555 
556 /** Dequantize a value given a 16-bit asymmetric quantization scheme
557  *
558  * @param[in] value Value to dequantize
559  * @param[in] qinfo Quantization information to use for dequantizing
560  *
561  * @return Dequantized value
562  */
dequantize_qasymm16(uint16_t value,const UniformQuantizationInfo & qinfo)563 inline float dequantize_qasymm16(uint16_t value, const UniformQuantizationInfo &qinfo)
564 {
565     return (static_cast<int>(value) - qinfo.offset) * qinfo.scale;
566 }
567 
568 /** Quantize a value given a 16-bit asymmetric quantization scheme
569  *
570  * @param[in] value Value to quantize
571  * @param[in] qinfo Quantization information to use for quantizing
572  *
573  * @return Quantized value
574  */
quantize_qasymm16(float value,const QuantizationInfo & qinfo)575 inline uint16_t quantize_qasymm16(float value, const QuantizationInfo &qinfo)
576 {
577     return quantize_qasymm16(value, qinfo.uniform());
578 }
579 
580 /** Dequantize a value given a 16-bit asymmetric quantization scheme
581  *
582  * @param[in] value Value to dequantize
583  * @param[in] qinfo Quantization information to use for dequantizing
584  *
585  * @return Dequantized value
586  */
dequantize_qasymm16(uint16_t value,const QuantizationInfo & qinfo)587 inline float dequantize_qasymm16(uint16_t value, const QuantizationInfo &qinfo)
588 {
589     return dequantize_qasymm16(value, qinfo.uniform());
590 }
591 
592 /*
593  * In case of requantization of a quantized input tensor to an output tensor with another quantization
594  * instead of applying dequantization and then a quantization functions, we just compute new scale and
595  * offset.
596  *
597  * Assuming:
598  *   - q_i as input quantized value
599  *   - q_o as output quantized value
600  *   - z_i as input quantization offset value
601  *   - z_o as output quantization offset value
602  *   - s_i as input quantization scale value
603  *   - s_o as output quantization scale value
604  *   - z_n as new quantization offset value
605  *   - s_n as new quantization scale value
606  *
607  * q_o = ( q_i - z_i ) * s_i / s_o + z_o
608  *
609  * We can rewrite the formula as:
610  *
611  * q_o = ( q_i * s_i / s_o ) - z_i * s_i / s_o + z_o
612  *
613  * q_o = q_i / s_n + z_n
614  *
615  * Where:
616  *
617  * s_n = s_o / s_i
618  *
619  * z_n = - z_i * s_i / s_o + z_o
620  *
621  */
compute_requantization_scale_offset(const UniformQuantizationInfo & uqinfo_in,const UniformQuantizationInfo & uqinfo_out)622 inline UniformQuantizationInfo compute_requantization_scale_offset(const UniformQuantizationInfo &uqinfo_in, const UniformQuantizationInfo &uqinfo_out)
623 {
624     float   scale_to_apply  = uqinfo_out.scale;
625     int32_t offset_to_apply = uqinfo_out.offset;
626 
627     scale_to_apply /= uqinfo_in.scale;
628     // In order to minimize flooring we convert the offset to a float,
629     // then compute the new offset in the float domain,
630     // finally we convert it back as int32_t
631     offset_to_apply -= static_cast<int32_t>(static_cast<float>(uqinfo_in.offset) * uqinfo_in.scale / uqinfo_out.scale);
632     return UniformQuantizationInfo(scale_to_apply, offset_to_apply);
633 }
634 
635 } // namespace arm_compute
636 #endif /* ARM_COMPUTE_QUANTIZATION_INFO_H */
637