blob: 5e6e5b349c96f0a083b1ebb7af0965c4e30a06d7 [file] [log] [blame]
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001/*
2 * Copyright (c) 2019 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/Rounding.h"
Manuel Bottini3689fcd2019-06-14 17:18:12 +010028#include "utils/misc/Utility.h"
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010029
30#include <cstddef>
31#include <vector>
32
33namespace arm_compute
34{
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +010035using qasymm8_t = uint8_t; /**< 8 bit quantized asymmetric scalar value */
36using qsymm16_t = int16_t; /**< 16 bit quantized symmetric scalar value */
37using qasymm16_t = uint16_t; /**< 16 bit quantized asymmetric scalar value */
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010038
39/** Quantization info when assuming per layer quantization */
40struct UniformQuantizationInfo
41{
42 /** Default constructor */
43 UniformQuantizationInfo()
44 : scale(0.f), offset(0)
45 {
46 }
47 /** Constructor
48 *
49 * @param[in] scale Quantization scale
50 * @param[in] offset Quantization offset
51 */
52 UniformQuantizationInfo(float scale, int32_t offset)
53 : scale(scale), offset(offset)
54 {
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 */
71 QuantizationInfo() noexcept
Georgios Pinitas3d13af82019-06-04 13:04:16 +010072 : _scale(),
73 _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010074 {
75 }
76 /** Construct quantization info.
77 *
78 * @note Used for symmetric quantization
79 *
80 * @param[in] scale Scale.
81 */
82 QuantizationInfo(float scale)
Georgios Pinitas3d13af82019-06-04 13:04:16 +010083 : _scale(1, scale), _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010084 {
85 }
86 /** Construct quantization info.
87 *
88 * @note Used for asymmetric quantization
89 *
90 * @param[in] scale Scale.
91 * @param[in] offset Offset.
92 */
93 QuantizationInfo(float scale, int offset)
Georgios Pinitas3d13af82019-06-04 13:04:16 +010094 : _scale(1, scale), _offset(1, offset)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +010095 {
96 }
97 /** Construct quantization info.
98 *
99 * @note Used for symmetric per channel quantization
100 *
101 * @param[in] scale Scale.
102 */
103 QuantizationInfo(std::vector<float> scale)
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100104 : _scale(scale), _offset()
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100105 {
106 }
Michalis Spyrou29a01c92019-08-22 11:44:04 +0100107 /** Construct quantization info.
108 *
109 * @note Used for asymmetric per channel quantization
110 *
111 * @param[in] scale Scale.
112 * @param[in] offset Offset.
113 */
114 QuantizationInfo(std::vector<float> scale, std::vector<int32_t> offset)
115 : _scale(scale), _offset(offset)
116 {
117 }
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100118 /** Scale vector accessor
119 *
120 * @return A reference to quantization scale metadata
121 */
122 const std::vector<float> &scale() const
123 {
124 return _scale;
125 }
126 /** Offset vector accessor
127 *
128 * @return A reference to quantization offset metadata
129 */
130 const std::vector<int32_t> &offset() const
131 {
132 return _offset;
133 }
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100134 /** Indicates whether this QuantizationInfo has valid settings or not
135 *
136 * @return True if the this has invalid settings.
137 */
138 bool empty() const
139 {
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100140 return _scale.empty() && _offset.empty();
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100141 }
142 /** Return per layer quantization info
143 *
144 * @return Uniform quantization information in case of empty information zero is returned in the respective fields
145 */
146 UniformQuantizationInfo uniform() const
147 {
148 UniformQuantizationInfo uqinfo;
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100149 uqinfo.scale = _scale.empty() ? 0 : _scale[0];
150 uqinfo.offset = _offset.empty() ? 0 : _offset[0];
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100151
152 return uqinfo;
153 }
154
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100155private:
156 std::vector<float> _scale; /**< Vector containing scaling factors */
157 std::vector<int32_t> _offset; /**< Vector containing zero offsets */
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100158};
159
160/** Check whether two quantization info are equal.
161 *
162 * @param[in] lhs RHS quantization info.
163 * @param[in] rhs LHS quantization info.
164 *
165 * @return True if the given quantization info is the same.
166 */
167inline bool operator==(const QuantizationInfo &lhs, const QuantizationInfo &rhs)
168{
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100169 return (lhs.scale() == rhs.scale()) && (lhs.offset() == rhs.offset());
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100170}
171
172/** Check whether two quantization info are not equal.
173 *
174 * @param[in] lhs RHS quantization info.
175 * @param[in] rhs LHS quantization info.
176 *
177 * @return True if the given quantization info is the same.
178 */
179inline bool operator!=(const QuantizationInfo &lhs, const QuantizationInfo &rhs)
180{
181 return !(operator==(lhs, rhs));
182}
183
184/** Check whether two quantization info are equal.
185 *
186 * @param[in] lhs RHS quantization info.
187 * @param[in] rhs LHS quantization info.
188 *
189 * @return True if the given quantization info is the same.
190 */
191inline bool operator==(const UniformQuantizationInfo &lhs, const UniformQuantizationInfo &rhs)
192{
193 return (lhs.scale == rhs.scale) && (lhs.offset == rhs.offset);
194}
195
196/** Check whether two quantization info are not equal.
197 *
198 * @param[in] lhs RHS quantization info.
199 * @param[in] rhs LHS quantization info.
200 *
201 * @return True if the given quantization info is the same.
202 */
203inline bool operator!=(const UniformQuantizationInfo &lhs, const UniformQuantizationInfo &rhs)
204{
205 return !(operator==(lhs, rhs));
206}
207
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100208/** Quantize a value given a 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100209 *
210 * @param[in] value Value to quantize
211 * @param[in] qinfo Quantization information to use for quantizing
212 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
213 *
214 * @return Quantized value
215 */
216inline uint8_t quantize_qasymm8(float value, const UniformQuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
217{
218 int quantized = arm_compute::round(value / qinfo.scale, rounding_policy) + qinfo.offset;
219 quantized = std::max(0, std::min(quantized, 255));
220 return quantized;
221}
222
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100223/** Quantize a value given a 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100224 *
225 * @param[in] value Value to quantize
226 * @param[in] qinfo Quantization information to use for quantizing
227 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
228 *
229 * @return Quantized value
230 */
231inline uint8_t quantize_qasymm8(float value, const QuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
232{
233 UniformQuantizationInfo uqinfo = qinfo.uniform();
234 int quantized = arm_compute::round(value / uqinfo.scale, rounding_policy) + uqinfo.offset;
235 quantized = std::max(0, std::min(quantized, 255));
236 return quantized;
237}
238
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100239/** Quantize a value given a 8-bit symmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100240 *
241 * @param[in] value Value to quantize
242 * @param[in] qinfo Quantization information to use for quantizing
243 *
244 * @return Quantized value
245 */
246inline int8_t quantize_qsymm8(float value, const QuantizationInfo &qinfo)
247{
248 int quantized = arm_compute::round(value / qinfo.uniform().scale, RoundingPolicy::TO_NEAREST_UP);
249 quantized = std::max(-128, std::min(quantized, 127));
250 return quantized;
251}
252
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100253/** Dequantize a value given a 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100254 *
255 * @param[in] value Value to dequantize
256 * @param[in] qinfo Quantization information to use for dequantizing
257 *
258 * @return Dequantized value
259 */
260inline float dequantize_qasymm8(uint8_t value, const UniformQuantizationInfo &qinfo)
261{
262 return (static_cast<int>(value) - qinfo.offset) * qinfo.scale;
263}
264
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100265/** Dequantize a value given a 8-bit asymmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100266 *
267 * @param[in] value Value to dequantize
268 * @param[in] qinfo Quantization information to use for dequantizing
269 *
270 * @return Dequantized value
271 */
272inline float dequantize_qasymm8(uint8_t value, const QuantizationInfo &qinfo)
273{
274 UniformQuantizationInfo uqinfo = qinfo.uniform();
275 return (static_cast<int>(value) - uqinfo.offset) * uqinfo.scale;
276}
277
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100278/** Dequantize a value given an 8-bit asymmetric quantization scheme
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100279 *
280 * @param[in] value Value to dequantize
281 * @param[in] scale Scale to use for dequantization
282 * @param[in] offset Zero-offset to use for dequantization
283 *
284 * @return Dequantized value
285 */
286inline float dequantize(uint8_t value, float scale, int32_t offset)
287{
288 return (static_cast<int>(value) - offset) * scale;
289}
290
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100291/** Dequantize a value given a 8-bit symmetric quantization scheme
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100292 *
293 * @param[in] value Value to dequantize
294 * @param[in] qinfo Quantization information to use for dequantizing
295 *
296 * @return Dequantized value
297 */
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100298inline float dequantize_qsymm8(int8_t value, const UniformQuantizationInfo &qinfo)
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100299{
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100300 return value * qinfo.scale;
301}
302
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100303/** Dequantize a value given a 8-bit symmetric quantization scheme
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100304 *
305 * @param[in] value Value to dequantize
306 * @param[in] scale Scale to use for dequantization
307 *
308 * @return Dequantized value
309 */
310inline float dequantize(int8_t value, float scale)
311{
312 return value * scale;
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100313}
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100314
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100315/** Dequantize a value given a 16-bit symmetric quantization scheme
Manuel Bottini10c53f12019-07-17 16:11:53 +0100316 *
317 * @param[in] value Value to dequantize
318 * @param[in] scale Scale to use for dequantization
319 *
320 * @return Dequantized value
321 */
322inline float dequantize(int16_t value, float scale)
323{
324 return value * scale;
325}
326
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100327/** Dequantize a value given a 16-bit asymmetric quantization scheme
328 *
329 * @param[in] value Value to dequantize
330 * @param[in] scale Scale to use for dequantization
331 * @param[in] offset Zero-offset to use for dequantization
332 *
333 * @return Dequantized value
334 */
335inline float dequantize(uint16_t value, float scale, int32_t offset)
336{
337 return (static_cast<int>(value) - offset) * scale;
338}
339
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100340/** Quantize a value given a 16-bit symmetric quantization scheme
341 *
342 * @param[in] value Value to quantize
343 * @param[in] qinfo Quantization information to use for quantizing
344 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
345 *
346 * @return Quantized value
347 */
348inline int16_t quantize_qsymm16(float value, const UniformQuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
349{
350 int quantized = arm_compute::round(value / qinfo.scale, rounding_policy);
351 quantized = arm_compute::utility::clamp<int, int16_t>(quantized);
352 return quantized;
353}
354
355/** Dequantize a value given a 16-bit symmetric quantization scheme
356 *
357 * @param[in] value Value to dequantize
358 * @param[in] qinfo Quantization information to use for dequantizing
359 *
360 * @return Dequantized value
361 */
362inline float dequantize_qsymm16(int16_t value, const UniformQuantizationInfo &qinfo)
363{
364 return value * qinfo.scale;
365}
366
367/** Quantize a value given a 16-bit symmetric quantization scheme
368 *
369 * @param[in] value Value to quantize
370 * @param[in] qinfo Quantization information to use for quantizing
371 *
372 * @return Quantized value
373 */
374inline int16_t quantize_qsymm16(float value, const QuantizationInfo &qinfo)
375{
376 return quantize_qsymm16(value, qinfo.uniform());
377}
378
379/** Dequantize a value given a 16-bit symmetric quantization scheme
380 *
381 * @param[in] value Value to dequantize
382 * @param[in] qinfo Quantization information to use for dequantizing
383 *
384 * @return Dequantized value
385 */
386inline float dequantize_qsymm16(int16_t value, const QuantizationInfo &qinfo)
387{
388 return dequantize_qsymm16(value, qinfo.uniform());
389}
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100390
391/** Quantize a value given a 16-bit asymmetric quantization scheme
392 *
393 * @param[in] value Value to quantize
394 * @param[in] qinfo Quantization information to use for quantizing
395 * @param[in] rounding_policy (Optional) Rounding policy to use. Default: nearest up
396 *
397 * @return Quantized value
398 */
399inline uint16_t quantize_qasymm16(float value, const UniformQuantizationInfo &qinfo, RoundingPolicy rounding_policy = RoundingPolicy::TO_NEAREST_UP)
400{
401 int quantized = arm_compute::round(value / qinfo.scale, rounding_policy) + qinfo.offset;
402 quantized = arm_compute::utility::clamp<int, uint16_t>(quantized);
403 return quantized;
404}
405
406/** Dequantize a value given a 16-bit asymmetric quantization scheme
407 *
408 * @param[in] value Value to dequantize
409 * @param[in] qinfo Quantization information to use for dequantizing
410 *
411 * @return Dequantized value
412 */
413inline float dequantize_qasymm16(uint16_t value, const UniformQuantizationInfo &qinfo)
414{
415 return (static_cast<int>(value) - qinfo.offset) * qinfo.scale;
416}
417
418/** Quantize a value given a 16-bit asymmetric quantization scheme
419 *
420 * @param[in] value Value to quantize
421 * @param[in] qinfo Quantization information to use for quantizing
422 *
423 * @return Quantized value
424 */
425inline uint16_t quantize_qasymm16(float value, const QuantizationInfo &qinfo)
426{
427 return quantize_qasymm16(value, qinfo.uniform());
428}
429
430/** Dequantize a value given a 16-bit asymmetric quantization scheme
431 *
432 * @param[in] value Value to dequantize
433 * @param[in] qinfo Quantization information to use for dequantizing
434 *
435 * @return Dequantized value
436 */
437inline float dequantize_qasymm16(uint16_t value, const QuantizationInfo &qinfo)
438{
439 return dequantize_qasymm16(value, qinfo.uniform());
440}
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100441} // namespace arm_compute
giuros01c9573f32019-06-20 10:30:17 +0100442#endif /*__ARM_COMPUTE_QUANTIZATION_INFO_H__ */