1 /**
2 * Copyright 2021 Huawei Technologies Co., Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "schema/inner/model_generated.h"
18 #include "src/common/quant_utils.h"
19 #include "src/lite_kernel.h"
20
21 namespace mindspore {
22 namespace lite {
GetMaxMinPerChannel(int channels,int one_filter_size,int i,int elem_count,const float * raw_datas,bool channel_at_first,float * desired_max,float * desired_min)23 STATUS GetMaxMinPerChannel(int channels, int one_filter_size, int i, int elem_count, const float *raw_datas,
24 bool channel_at_first, float *desired_max, float *desired_min) {
25 float min = FLT_MAX;
26 float max = -FLT_MAX;
27 // find min and max
28 for (int j = 0; j < one_filter_size; j++) {
29 auto index = j + i * one_filter_size;
30 if (!channel_at_first) {
31 index = j * channels + i;
32 }
33 if (index >= elem_count) {
34 MS_LOG(ERROR) << "over flow!";
35 return RET_ERROR;
36 }
37 min = std::min(min, raw_datas[index]);
38 max = std::max(max, raw_datas[index]);
39 }
40 *desired_max = max;
41 *desired_min = min;
42 return RET_OK;
43 }
44
CalQuantizationParams(schema::QuantParamT * quant_param,double real_min,double real_max,bool narrow_range,int quant_max,int quant_min,int num_bits)45 STATUS CalQuantizationParams(schema::QuantParamT *quant_param, double real_min, double real_max, bool narrow_range,
46 int quant_max, int quant_min, int num_bits) {
47 MS_ASSERT(quant_param != nullptr);
48 if (real_min > 0.0f) {
49 MS_LOG(DEBUG) << "min " << real_min << " is bigger then 0, set to 0, this may course low precision";
50 real_min = 0.0f;
51 }
52 if (real_max < 0.0f) {
53 MS_LOG(DEBUG) << "real_max " << real_max << " is smaller than 0, set to 0, this may course low precision";
54 real_max = 0.0f;
55 }
56 if (real_min > real_max) {
57 MS_LOG(ERROR) << "cal error while min" << real_min << ">" << real_max;
58 return RET_PARAM_INVALID;
59 }
60 if (real_min == real_max) {
61 if (real_min != 0.0f) {
62 MS_LOG(ERROR) << "min and max should both be zero if they are equal to each other";
63 return RET_ERROR;
64 }
65 MS_LOG(WARNING) << "The maximum and minimum values are equal to 0.";
66 quant_param->inited = true;
67 quant_param->min = real_min;
68 quant_param->max = real_max;
69 quant_param->scale = 1;
70 quant_param->zeroPoint = 0;
71 quant_param->narrowRange = narrow_range;
72 quant_param->numBits = num_bits;
73 return RET_OK;
74 }
75
76 auto quantMinFloat = static_cast<double>(quant_min);
77 auto quantMaxFloat = static_cast<double>(quant_max);
78 if (fabs(quantMaxFloat - quantMinFloat) <= 0.0f) {
79 MS_LOG(ERROR) << "divisor cannot be 0";
80 return RET_ERROR;
81 }
82 double scale = (real_max - real_min) / (quantMaxFloat - quantMinFloat);
83 if (fabs(scale) <= 0.0f) {
84 MS_LOG(ERROR) << "divisor 'scale' cannot be 0";
85 return RET_ERROR;
86 }
87 const double zeroPointFromMin = quantMinFloat - real_min / scale;
88 int zeroPoint = static_cast<int32_t>(std::round(zeroPointFromMin));
89
90 // The zero point should always be in the range of quantized value,
91 // [qmin, qmax].
92 MS_ASSERT(zeroPoint >= quant_min);
93 MS_ASSERT(zeroPoint <= quant_max);
94 quant_param->inited = true;
95 quant_param->min = real_min;
96 quant_param->max = real_max;
97 quant_param->scale = scale;
98 quant_param->zeroPoint = zeroPoint;
99 quant_param->narrowRange = narrow_range;
100 quant_param->numBits = num_bits;
101
102 return RET_OK;
103 }
104 } // namespace lite
105 } // namespace mindspore
106