1 #include "caffe2/core/logging.h" 2 #include "caffe2/utils/cpuid.h" 3 #include "l2_minimization.h" 18 GetNorm(
float begin,
float end,
float density, NormMinimization::Kind kind) {
22 if (NormMinimization::L2 == kind) {
25 norm = (end * end * end - begin * begin * begin) / 3;
30 float left_begin = std::min(0.0f, begin);
31 float left_end = std::min(0.0f, end);
32 assert(left_begin * left_begin >= left_end * left_end);
33 norm += (left_begin * left_begin - left_end * left_end) / 2;
35 float right_begin = std::max(0.0f, begin);
36 float right_end = std::max(0.0f, end);
37 assert(right_end * right_end >= right_begin * right_begin);
38 norm += (right_end * right_end - right_begin * right_begin) / 2;
41 return density * norm;
47 adjust_hist_to_include_zero(
const Histogram& hist,
float* min,
float* max) {
48 const vector<uint64_t> bins = *hist.GetHistogram();
51 int nbins = bins.size();
52 float bin_width = (*max - *min) / nbins;
55 int additional_nbins = 0;
59 additional_nbins = ceil(*min / bin_width);
60 offset = additional_nbins;
61 *min -= additional_nbins * bin_width;
63 }
else if (*max < 0) {
64 additional_nbins = ceil((-*max) / bin_width);
65 *max += additional_nbins * bin_width;
69 vector<float> bins_f(nbins + additional_nbins);
70 for (
int i = 0; i < nbins; ++i) {
71 bins_f[i + offset] = bins[i];
80 TensorQuantizationParams NormMinimization::NonlinearQuantizationParamsSearch(
82 bool preserve_sparsity,
84 if (preserve_sparsity) {
85 VLOG(2) <<
"l2_approx with symmetric quantization falls back to L2";
86 return ChooseQuantizationParams(hist, preserve_sparsity, precision);
88 VLOG(2) <<
"Using the nonlinear quantile search";
91 vector<float> bins_f(adjust_hist_to_include_zero(hist, &min, &max));
92 int nbins = bins_f.size();
93 float bin_width = (max - min) / nbins;
94 int dst_nbins = 1 << precision;
98 for (uint64_t x : bins_f) {
101 vector<uint64_t> CDF;
103 for (uint64_t x : bins_f) {
108 double stepsize = 0.00001;
109 double alpha = 0.0f, beta = 1.0f;
111 int end_bin = nbins - 1;
112 double norm_min = numeric_limits<double>::max();
114 while (alpha < beta) {
116 double next_alpha = alpha + stepsize;
117 double next_beta = beta - stepsize;
120 int i = start_bin, j = end_bin;
121 while (i < end_bin && CDF[i] < next_alpha * total)
123 while (j > start_bin && CDF[j] > next_beta * total)
128 int next_start_bin = start_bin, next_end_bin = end_bin;
129 if ((i - start_bin) > (end_bin - j)) {
139 if (next_start_bin == start_bin && next_end_bin == end_bin)
143 double dst_bin_width =
144 bin_width * (next_end_bin - next_start_bin + 1) / dst_nbins;
147 for (
int src_bin = 0; src_bin < nbins; ++src_bin) {
150 double src_bin_begin = (src_bin - next_start_bin) * bin_width;
151 double src_bin_end = src_bin_begin + bin_width;
154 int dst_bin_of_begin = std::min(
155 (1 << precision) - 1.,
156 std::max(0., floor(src_bin_begin / dst_bin_width)));
157 int dst_bin_of_end = std::min(
158 (1 << precision) - 1.,
159 std::max(0., floor(src_bin_end / dst_bin_width)));
161 double dst_bin_of_begin_center =
162 dst_bin_of_begin * dst_bin_width + dst_bin_width / 2;
163 double density = bins_f[src_bin] / bin_width;
164 if (dst_bin_of_begin == dst_bin_of_end) {
166 double delta_begin = src_bin_begin - dst_bin_of_begin_center;
167 double delta_end = src_bin_end - dst_bin_of_begin_center;
168 norm += GetNorm(delta_begin, delta_end, density, kind_);
170 double delta_begin = src_bin_begin - dst_bin_of_begin_center;
171 double delta_end = dst_bin_width / 2;
172 norm += GetNorm(delta_begin, delta_end, density, kind_);
174 norm += (dst_bin_of_end - dst_bin_of_begin - 1) *
175 GetNorm(-dst_bin_width / 2, dst_bin_width / 2, density, kind_);
177 double dst_bin_of_end_center =
178 dst_bin_of_end * dst_bin_width + dst_bin_width / 2;
179 delta_begin = -dst_bin_width / 2;
180 delta_end = src_bin_end - dst_bin_of_end_center;
181 norm += GetNorm(delta_begin, delta_end, density, kind_);
187 start_bin = next_start_bin;
188 end_bin = next_end_bin;
190 VLOG(2) <<
"best quantiation range " << start_bin <<
"," << end_bin + 1 <<
"," 193 double selected_sum = 0;
194 for (
int i = start_bin; i < end_bin + 1; ++i) {
195 selected_sum += bins_f[i];
197 VLOG(2) <<
"best quantization range covers " 198 << (double)selected_sum / total * 100 <<
" %%";
200 max = min + bin_width * (end_bin + 1);
201 min = min + bin_width * start_bin;
205 min, max, precision, preserve_sparsity);
208 TensorQuantizationParams NormMinimization::ChooseQuantizationParams(
210 bool preserve_sparsity,
212 VLOG(2) <<
"Using the brute force search";
214 vector<float> bins_f(adjust_hist_to_include_zero(hist, &min, &max));
215 int nbins = bins_f.size();
216 float bin_width = (max - min) / nbins;
218 int dst_nbins = 1 << precision;
220 int zero_bin = round(-min / bin_width);
222 vector<pair<int, float>> best_start_bins(nbins + 1);
228 #pragma omp parallel for schedule(dynamic) 230 for (
int nbins_selected = 1; nbins_selected <= nbins; ++nbins_selected) {
231 float norm_min = numeric_limits<float>::max();
232 int best_start_bin = 0;
234 int start_bin_begin = 0, start_bin_end = nbins - nbins_selected + 1;
235 if (preserve_sparsity) {
242 start_bin_begin = zero_bin - nbins_selected / 2;
243 start_bin_end = start_bin_begin + 1;
247 float dst_bin_width = bin_width * nbins_selected / dst_nbins;
250 for (start_bin = start_bin_begin; start_bin < start_bin_end; ++start_bin) {
255 if (kind_ == NormMinimization::L2 && cpuid.avx2() && cpuid.fma()) {
256 norm = internal::L2MinimizationKernelAVX2(
264 for (
int src_bin = 0; src_bin < nbins; ++src_bin) {
267 float src_bin_begin = (src_bin - start_bin) * bin_width;
268 float src_bin_end = src_bin_begin + bin_width;
271 int dst_bin_of_begin = std::min(
272 (1 << precision) - 1.0f,
273 std::max(0.0f, floorf(src_bin_begin / dst_bin_width)));
274 int dst_bin_of_end = std::min(
275 (1 << precision) - 1.0f,
276 std::max(0.0f, floorf(src_bin_end / dst_bin_width)));
278 float dst_bin_of_begin_center =
279 dst_bin_of_begin * dst_bin_width + dst_bin_width / 2;
280 float density = bins_f[src_bin] / bin_width;
281 float delta_begin = src_bin_begin - dst_bin_of_begin_center;
282 if (dst_bin_of_begin == dst_bin_of_end) {
284 float delta_end = src_bin_end - dst_bin_of_begin_center;
285 norm += GetNorm(delta_begin, delta_end, density, kind_);
287 float delta_end = dst_bin_width / 2;
288 norm += GetNorm(delta_begin, delta_end, density, kind_);
290 norm += (dst_bin_of_end - dst_bin_of_begin - 1) *
291 GetNorm(-dst_bin_width / 2, dst_bin_width / 2, density, kind_);
293 float dst_bin_of_end_center =
294 dst_bin_of_end * dst_bin_width + dst_bin_width / 2;
295 delta_begin = -dst_bin_width / 2;
296 delta_end = src_bin_end - dst_bin_of_end_center;
297 norm += GetNorm(delta_begin, delta_end, density, kind_);
302 if (norm < norm_min) {
304 best_start_bin = start_bin;
308 best_start_bins[nbins_selected] = {best_start_bin, norm_min};
311 float norm_min = numeric_limits<float>::max();
312 int best_nbins_selected = 1, best_start_bin = 0;
313 for (
int nbins_selected = 1; nbins_selected <= nbins; ++nbins_selected) {
314 float norm = best_start_bins[nbins_selected].second;
315 if (norm < norm_min) {
317 best_start_bin = best_start_bins[nbins_selected].first;
318 best_nbins_selected = nbins_selected;
323 for (
int i = 0; i < bins_f.size(); ++i) {
324 total_sum += bins_f[i];
326 float selected_sum = 0;
327 int i_begin = std::max(0, best_start_bin);
328 int i_end = std::min(nbins, best_start_bin + best_nbins_selected);
329 for (
int i = i_begin; i < i_end; ++i) {
330 selected_sum += bins_f[i];
332 VLOG(2) <<
"best quantization range covers " << selected_sum / total_sum * 100
335 max = min + bin_width * (best_start_bin + best_nbins_selected);
336 min = min + bin_width * (best_start_bin);
339 return qfactory->ChooseQuantizationParams(
340 min, max, precision, preserve_sparsity);
TensorQuantizationParams ChooseQuantizationParams(float min, float max, int precision, bool preserve_sparsity, bool is_signed=false) const
Choose quantization scale and zero_point that maps floating-point range [min, max] to the integer ran...
Identification of an Intel CPU.
bin_width = (max - min)/nbins ith bin (zero-based indexing) contains [i*bin_width, (i+1)*bin_width) with an exception that (nbins - 1)th bin contains [(nbins-1)*bin_width, nbins*bin_width]