blob: 5bda746e09b9b7d76d3e423c861439ae6ec7f4f3 [file] [log] [blame]
Chunosovd621bca2017-11-03 17:33:15 +07001/*
Michalis Spyrou299fdd32019-05-01 13:03:59 +01002 * Copyright (c) 2017-2019 ARM Limited.
Chunosovd621bca2017-11-03 17:33:15 +07003 *
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#include "arm_compute/core/utils/quantization/AsymmHelpers.h"
Michele Di Giorgiodf4cf572019-10-09 15:32:39 +010025#include "arm_compute/core/Helpers.h"
Chunosovd621bca2017-11-03 17:33:15 +070026
27#include <cmath>
28#include <limits>
29#include <numeric>
30
Michele Di Giorgiod87a7b22019-09-10 10:42:27 +010031namespace arm_compute
32{
33namespace quantization
34{
Michalis Spyrou299fdd32019-05-01 13:03:59 +010035constexpr int64_t fixed_point_one_Q0 = (1LL << 31);
Gian Marco Iodice3139f032018-11-05 14:26:32 +000036constexpr float epsilon = 0.00001f;
Chunosovf450caa2017-11-08 16:09:35 +070037
Michalis Spyroue7be8a02019-12-12 16:16:09 +000038Status calculate_quantized_multiplier(float multiplier, int32_t *quant_multiplier, int32_t *shift)
Manuel Bottini07263982019-10-17 18:37:26 +010039{
Michele Di Giorgio35c37942019-12-03 19:34:30 +000040 if(multiplier >= 1.f)
Manuel Bottini07263982019-10-17 18:37:26 +010041 {
42 Status status = calculate_quantized_multiplier_greater_than_one(multiplier, quant_multiplier, shift);
43 *shift *= -1;
44 return status;
45 }
46 else
47 {
48 return calculate_quantized_multiplier_less_than_one(multiplier, quant_multiplier, shift);
49 }
50}
51
Michalis Spyroue7be8a02019-12-12 16:16:09 +000052Status calculate_quantized_multiplier_less_than_one(float multiplier,
53 int32_t *quant_multiplier,
54 int32_t *right_shift)
Chunosovd621bca2017-11-03 17:33:15 +070055{
56 ARM_COMPUTE_RETURN_ERROR_ON(quant_multiplier == nullptr);
57 ARM_COMPUTE_RETURN_ERROR_ON(right_shift == nullptr);
Gian Marco Iodice3139f032018-11-05 14:26:32 +000058 ARM_COMPUTE_RETURN_ERROR_ON(multiplier < -epsilon);
59 ARM_COMPUTE_RETURN_ERROR_ON(multiplier > 1.0f + epsilon);
Gian Marco Iodice3139f032018-11-05 14:26:32 +000060 if(std::fabs(0.0f - multiplier) < epsilon)
Chunosovd621bca2017-11-03 17:33:15 +070061 {
62 *quant_multiplier = 0;
63 *right_shift = 0;
Michele Di Giorgiod87a7b22019-09-10 10:42:27 +010064 return Status{};
Chunosovd621bca2017-11-03 17:33:15 +070065 }
Gian Marco Iodice3139f032018-11-05 14:26:32 +000066
Michalis Spyroue7be8a02019-12-12 16:16:09 +000067 int shift_exp = 0;
68 const double q = std::frexp(multiplier, &shift_exp);
69 *right_shift = -1 * shift_exp;
70 auto q_fixed = static_cast<int64_t>(support::cpp11::round(q * fixed_point_one_Q0));
Chunosovf450caa2017-11-08 16:09:35 +070071 ARM_COMPUTE_RETURN_ERROR_ON(q_fixed > fixed_point_one_Q0);
72 if(q_fixed == fixed_point_one_Q0)
Chunosovd621bca2017-11-03 17:33:15 +070073 {
74 q_fixed /= 2;
75 --*right_shift;
76 }
77 ARM_COMPUTE_RETURN_ERROR_ON(*right_shift < 0);
78 ARM_COMPUTE_RETURN_ERROR_ON(q_fixed > std::numeric_limits<int32_t>::max());
Chunosovf450caa2017-11-08 16:09:35 +070079 *quant_multiplier = static_cast<int32_t>(q_fixed);
Chunosovd621bca2017-11-03 17:33:15 +070080
Michele Di Giorgiod87a7b22019-09-10 10:42:27 +010081 return Status{};
Chunosovf450caa2017-11-08 16:09:35 +070082}
83
Michalis Spyroue7be8a02019-12-12 16:16:09 +000084Status calculate_quantized_multiplier_greater_than_one(float multiplier,
85 int32_t *quantized_multiplier,
86 int32_t *left_shift)
Chunosovf450caa2017-11-08 16:09:35 +070087{
88 ARM_COMPUTE_RETURN_ERROR_ON(quantized_multiplier == nullptr);
89 ARM_COMPUTE_RETURN_ERROR_ON(left_shift == nullptr);
90 ARM_COMPUTE_RETURN_ERROR_ON(multiplier < 1.f);
Michalis Spyroue7be8a02019-12-12 16:16:09 +000091
92 int shift_exp = 0;
93 const double q = std::frexp(multiplier, &shift_exp);
94 *left_shift = shift_exp;
95 auto q_fixed = static_cast<int64_t>(support::cpp11::round(q * fixed_point_one_Q0));
Chunosovf450caa2017-11-08 16:09:35 +070096 ARM_COMPUTE_RETURN_ERROR_ON(q_fixed > fixed_point_one_Q0);
97 if(q_fixed == fixed_point_one_Q0)
98 {
99 q_fixed /= 2;
100 ++*left_shift;
101 }
102 ARM_COMPUTE_RETURN_ERROR_ON(*left_shift < 0);
103 ARM_COMPUTE_RETURN_ERROR_ON(q_fixed > std::numeric_limits<int32_t>::max());
104 *quantized_multiplier = static_cast<int32_t>(q_fixed);
105
Michele Di Giorgiod87a7b22019-09-10 10:42:27 +0100106 return Status{};
Chunosovf450caa2017-11-08 16:09:35 +0700107}
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100108
Michele Di Giorgiof29d1b72019-10-29 10:58:13 +0000109arm_compute::Status calculate_quantized_multipliers(const QuantizationInfo &iq_info,
110 const QuantizationInfo &wq_info,
111 const QuantizationInfo &oq_info,
112 GEMMLowpOutputStageInfo &stage_info)
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100113{
114 ARM_COMPUTE_RETURN_ERROR_ON(iq_info.scale().empty());
115 ARM_COMPUTE_RETURN_ERROR_ON(wq_info.scale().empty());
116 ARM_COMPUTE_RETURN_ERROR_ON(oq_info.scale().empty());
117
118 const unsigned int size = wq_info.scale().size();
119
120 auto &quant_multipliers = stage_info.gemmlowp_multipliers;
121 auto &quant_shifts = stage_info.gemmlowp_shifts;
122 quant_multipliers.resize(size);
123 quant_shifts.resize(size);
124
125 const auto &w_scales = wq_info.scale();
126 const float i_scale = iq_info.scale().at(0);
127 const float o_scale = oq_info.scale().at(0);
128
129 for(unsigned int i = 0; i < size; ++i)
130 {
131 const float multiplier = i_scale * w_scales[i] / o_scale;
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000132 int32_t quant_multiplier = 0;
133 int32_t quant_shift = 0;
Michele Di Giorgiof29d1b72019-10-29 10:58:13 +0000134 ARM_COMPUTE_RETURN_ON_ERROR(calculate_quantized_multiplier(multiplier, &quant_multiplier, &quant_shift));
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100135 quant_multipliers[i] = quant_multiplier;
136 quant_shifts[i] = quant_shift;
137 }
138
139 // Legacy part
140 stage_info.gemmlowp_shift = quant_shifts[0];
141 stage_info.gemmlowp_multiplier = quant_multipliers[0];
142
143 return Status{};
144}
145
Michele Di Giorgiod87a7b22019-09-10 10:42:27 +0100146std::pair<int, int> get_min_max_values_from_quantized_data_type(DataType data_type)
147{
148 int min_quant_val = 0;
149 int max_quant_val = 0;
150 switch(data_type)
151 {
152 case DataType::QASYMM8:
153 min_quant_val = std::numeric_limits<uint8_t>::min();
154 max_quant_val = std::numeric_limits<uint8_t>::max();
155 break;
156 case DataType::QSYMM8:
157 min_quant_val = std::numeric_limits<int8_t>::min();
158 max_quant_val = std::numeric_limits<int8_t>::max();
159 break;
160 case DataType::QASYMM16:
161 min_quant_val = std::numeric_limits<uint16_t>::min();
162 max_quant_val = std::numeric_limits<uint16_t>::max();
163 break;
164 case DataType::QSYMM16:
165 min_quant_val = std::numeric_limits<int16_t>::min();
166 max_quant_val = std::numeric_limits<int16_t>::max();
167 break;
168 default:
169 ARM_COMPUTE_ERROR("Unsupported data type");
170 }
171 return std::make_pair(min_quant_val, max_quant_val);
172}
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000173void compute_quantized_multipliers_and_shifts(const ITensorInfo *input,
174 const ITensorInfo *weights,
175 const ITensorInfo *output,
176 unsigned int idx_ofms,
177 int32_t *output_multipliers_ptr,
178 int32_t *output_shifts_ptr)
Michele Di Giorgiodf4cf572019-10-09 15:32:39 +0100179{
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000180 const unsigned int num_filters = is_data_type_quantized_per_channel(weights->data_type()) ? weights->dimension(idx_ofms) : 1;
Michele Di Giorgiodf4cf572019-10-09 15:32:39 +0100181
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000182 const UniformQuantizationInfo iq_info = input->quantization_info().uniform();
183 const QuantizationInfo wq_info = weights->quantization_info();
184 const UniformQuantizationInfo oq_info = output->quantization_info().uniform();
Michele Di Giorgiodf4cf572019-10-09 15:32:39 +0100185
186 for(unsigned int i = 0; i < num_filters; ++i)
187 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000188 int32_t output_multiplier = 0;
189 int32_t output_shift = 0;
Michele Di Giorgiodf4cf572019-10-09 15:32:39 +0100190 const float multiplier = iq_info.scale * wq_info.scale()[i] / oq_info.scale;
Michele Di Giorgio14cbfb22019-10-23 10:53:10 +0100191 calculate_quantized_multiplier(multiplier, &output_multiplier, &output_shift);
Michele Di Giorgiodf4cf572019-10-09 15:32:39 +0100192
193 output_multipliers_ptr[i] = output_multiplier;
194 output_shifts_ptr[i] = output_shift;
195 }
196}
Michele Di Giorgiod87a7b22019-09-10 10:42:27 +0100197} // quantization
198} // arm_compute