blob: ddf1342e3227ced70c10a862459edb92987d7bc0 [file] [log] [blame]
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001/*
Pablo Marquez Tellod75cd8a2022-05-26 14:19:39 +01002 * Copyright (c) 2019-2022 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
Manuel Bottini15e4d872020-04-01 12:35:36 +010027#include "arm_compute/core/Error.h"
Giorgio Arena433ea492021-05-26 15:32:50 +010028#include "arm_compute/core/Rounding.h"
29#include "support/ToolchainSupport.h"
30#include "utils/misc/Utility.h"
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010031
32#include <cstddef>
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +000033#include <type_traits>
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010034#include <vector>
35
36namespace arm_compute
37{
Michalis Spyrou8d4d1b82019-11-28 11:31:23 +000038using qasymm8_signed_t = int8_t; /**< 8 bit signed quantized asymmetric scalar value */
39using qasymm8_t = uint8_t; /**< 8 bit quantized asymmetric scalar value */
40using qsymm16_t = int16_t; /**< 16 bit quantized symmetric scalar value */
41using qasymm16_t = uint16_t; /**< 16 bit quantized asymmetric scalar value */
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010042
43/** Quantization info when assuming per layer quantization */
44struct UniformQuantizationInfo
45{
46 /** Default constructor */
47 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 */
56 UniformQuantizationInfo(float scale, int32_t offset)
57 : scale(scale), offset(offset)
58 {
59 }
60 /** Checks if the scale and offset are both zero */
61 bool empty() const
62 {
63 return (scale == 0) && (offset == 0);
64 }
65
66 float scale;
67 int32_t offset;
68};
69
70/** Quantization information */
Georgios Pinitas3d13af82019-06-04 13:04:16 +010071class QuantizationInfo
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010072{
Georgios Pinitas3d13af82019-06-04 13:04:16 +010073public:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010074 /** Default constructor */
75 QuantizationInfo() noexcept
Georgios Pinitas3d13af82019-06-04 13:04:16 +010076 : _scale(),
77 _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010078 {
79 }
80 /** Construct quantization info.
81 *
82 * @note Used for symmetric quantization
83 *
84 * @param[in] scale Scale.
85 */
86 QuantizationInfo(float scale)
Georgios Pinitas3d13af82019-06-04 13:04:16 +010087 : _scale(1, scale), _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010088 {
89 }
90 /** Construct quantization info.
91 *
92 * @note Used for asymmetric quantization
93 *
94 * @param[in] scale Scale.
95 * @param[in] offset Offset.
96 */
97 QuantizationInfo(float scale, int offset)
Georgios Pinitas3d13af82019-06-04 13:04:16 +010098 : _scale(1, scale), _offset(1, offset)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010099 {
100 }
101 /** Construct quantization info.
102 *
103 * @note Used for symmetric per channel quantization
104 *
105 * @param[in] scale Scale.
106 */
107 QuantizationInfo(std::vector<float> scale)
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100108 : _scale(scale), _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100109 {
110 }
Michalis Spyrou29a01c92019-08-22 11:44:04 +0100111 /** Construct quantization info.
112 *
113 * @note Used for asymmetric per channel quantization
114 *
115 * @param[in] scale Scale.
116 * @param[in] offset Offset.
117 */
118 QuantizationInfo(std::vector<float> scale, std::vector<int32_t> offset)
119 : _scale(scale), _offset(offset)
120 {
121 }
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100122 /** Scale vector accessor
123 *
124 * @return A reference to quantization scale metadata
125 */
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 */
134 const std::vector<int32_t> &offset() const
135 {
136 return _offset;
137 }
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100138 /** Indicates whether this QuantizationInfo has valid settings or not
139 *
140 * @return True if the this has invalid settings.
141 */
142 bool empty() const
143 {
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100144 return _scale.empty() && _offset.empty();
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100145 }
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 */
150 UniformQuantizationInfo uniform() const
151 {
152 UniformQuantizationInfo uqinfo;
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100153 uqinfo.scale = _scale.empty() ? 0 : _scale[0];
154 uqinfo.offset = _offset.empty() ? 0 : _offset[0];
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100155
156 return uqinfo;
157 }
158
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100159private:
160 std::vector<float> _scale; /**< Vector containing scaling factors */
161 std::vector<int32_t> _offset; /**< Vector containing zero offsets */
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100162};
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 */
171inline bool operator==(const QuantizationInfo &lhs, const QuantizationInfo &rhs)
172{
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100173 return (lhs.scale() == rhs.scale()) && (lhs.offset() == rhs.offset());
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100174}
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 */
183inline 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 */
195inline 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 */
207inline bool operator!=(const UniformQuantizationInfo &lhs, const UniformQuantizationInfo &rhs)
208{
209 return !(operator==(lhs, rhs));
210}
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000211template <typename QUANTIZED_TYPE = uint8_t>
212struct 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.");
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100217
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000218 /** Quantize a value given a 8-bit asymmetric quantization scheme
219 *
Giorgio Arena433ea492021-05-26 15:32:50 +0100220 * @param[in] value Value to quantize
221 * @param[in] qinfo Quantization information to use for quantizing
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000222 *
223 * @return Quantized value
224 */
Giorgio Arena433ea492021-05-26 15:32:50 +0100225 static inline QUANTIZED_TYPE quantize(float value, const UniformQuantizationInfo &qinfo)
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000226 {
227 ARM_COMPUTE_ERROR_ON(qinfo.scale == 0);
Giorgio Arena433ea492021-05-26 15:32:50 +0100228 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 */
240 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);
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000248 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 */
275 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 */
287 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
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100295 *
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 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000302template <typename INFO_TYPE>
303inline uint8_t quantize_qasymm8(float value, const INFO_TYPE &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100304{
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000305 return Qasymm8QuantizationHelper<uint8_t>::quantize(value, qinfo, rounding_policy);
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100306}
307
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000308/** Quantize a value given a signed 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100309 *
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 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000316template <typename INFO_TYPE>
317inline 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 +0100318{
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000319 return Qasymm8QuantizationHelper<int8_t>::quantize(value, qinfo, rounding_policy);
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100320}
321
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100322/** Quantize a value given a 8-bit symmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100323 *
324 * @param[in] value Value to quantize
325 * @param[in] qinfo Quantization information to use for quantizing
326 *
327 * @return Quantized value
328 */
329inline 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
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100336/** 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 */
344inline 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
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000351/** Dequantize a value given an unsigned 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100352 *
353 * @param[in] value Value to dequantize
354 * @param[in] qinfo Quantization information to use for dequantizing
355 *
356 * @return Dequantized value
357 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000358template <typename INFO_TYPE>
359inline float dequantize_qasymm8(uint8_t value, const INFO_TYPE &qinfo)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100360{
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000361 return Qasymm8QuantizationHelper<uint8_t>::dequantize(value, qinfo);
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100362}
363
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000364/** Dequantize a value given a signed 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100365 *
366 * @param[in] value Value to dequantize
367 * @param[in] qinfo Quantization information to use for dequantizing
368 *
369 * @return Dequantized value
370 */
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000371template <typename INFO_TYPE>
372inline float dequantize_qasymm8_signed(int8_t value, const INFO_TYPE &qinfo)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100373{
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000374 return Qasymm8QuantizationHelper<int8_t>::dequantize(value, qinfo);
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100375}
376
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100377/** Dequantize a value given an 8-bit asymmetric quantization scheme
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100378 *
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 */
385inline float dequantize(uint8_t value, float scale, int32_t offset)
386{
387 return (static_cast<int>(value) - offset) * scale;
388}
389
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100390/** Dequantize a value given a 8-bit symmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100391 *
392 * @param[in] value Value to dequantize
393 * @param[in] qinfo Quantization information to use for dequantizing
394 *
395 * @return Dequantized value
396 */
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100397inline float dequantize_qsymm8(int8_t value, const UniformQuantizationInfo &qinfo)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100398{
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100399 return value * qinfo.scale;
400}
401
Pablo Marquez Tellod75cd8a2022-05-26 14:19:39 +0100402inline 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
Pablo Marquez Tello16789a12022-07-25 14:41:26 +0100412inline 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
Viet-Hoa Dob042e392022-06-21 15:56:15 +0100422inline 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
Viet-Hoa Do29db3d22022-08-10 11:56:49 +0100433inline 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
443inline 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
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100453/** Dequantize a value given a 8-bit symmetric quantization scheme
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100454 *
455 * @param[in] value Value to dequantize
456 * @param[in] scale Scale to use for dequantization
457 *
458 * @return Dequantized value
459 */
460inline float dequantize(int8_t value, float scale)
461{
462 return value * scale;
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100463}
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100464
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100465/** Dequantize a value given a 16-bit symmetric quantization scheme
Manuel Bottini10c53f12019-07-17 16:11:53 +0100466 *
467 * @param[in] value Value to dequantize
468 * @param[in] scale Scale to use for dequantization
469 *
470 * @return Dequantized value
471 */
472inline float dequantize(int16_t value, float scale)
473{
474 return value * scale;
475}
476
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100477/** 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 */
485inline float dequantize(uint16_t value, float scale, int32_t offset)
486{
487 return (static_cast<int>(value) - offset) * scale;
488}
489
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100490/** 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 */
498inline 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 */
512inline 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 */
524inline 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 */
536inline float dequantize_qsymm16(int16_t value, const QuantizationInfo &qinfo)
537{
538 return dequantize_qsymm16(value, qinfo.uniform());
539}
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100540
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 */
549inline 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 */
563inline 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 */
575inline 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 */
587inline float dequantize_qasymm16(uint16_t value, const QuantizationInfo &qinfo)
588{
589 return dequantize_qasymm16(value, qinfo.uniform());
590}
Manuel Bottini4370cff2020-02-07 16:31:59 +0000591
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 */
622inline 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
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100635} // namespace arm_compute
Sang-Hoon Parkae6ef7c2019-11-13 16:51:45 +0000636#endif /* ARM_COMPUTE_QUANTIZATION_INFO_H */