Imported Upstream version 1.18.0
[platform/core/ml/nnfw.git] / compiler / luci-interpreter / src / kernels / Utils.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
3  * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *    http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include "kernels/Utils.h"
19
20 #include <cassert>
21 #include <cmath>
22 #include <limits>
23 #include <stdexcept>
24
25 namespace luci_interpreter
26 {
27 namespace kernels
28 {
29
30 void calculateActivationRange(Activation activation, float *activation_min, float *activation_max)
31 {
32   switch (activation)
33   {
34     case Activation::NONE:
35     case Activation::TANH:
36       *activation_min = std::numeric_limits<float>::lowest();
37       *activation_max = std::numeric_limits<float>::max();
38       break;
39     case Activation::RELU:
40       *activation_min = 0;
41       *activation_max = std::numeric_limits<float>::max();
42       break;
43     case Activation::RELU_N1_TO_1:
44       *activation_min = -1;
45       *activation_max = 1;
46       break;
47     case Activation::RELU6:
48       *activation_min = 0;
49       *activation_max = 6;
50       break;
51     default:
52       throw std::runtime_error("Unsupported activation.");
53   }
54 }
55
56 static void calculateActivationRangeQuantizedImpl(Activation activation, int32_t qmin, int32_t qmax,
57                                                   const Tensor *output, int32_t *activation_min,
58                                                   int32_t *activation_max)
59 {
60   const float scale = output->scale();
61   const int32_t zero_point = output->zero_point();
62
63   auto quantize = [scale, zero_point](float x) {
64     return zero_point + static_cast<int32_t>(std::round(x / scale));
65   };
66
67   switch (activation)
68   {
69     case Activation::NONE:
70     case Activation::TANH:
71       *activation_min = qmin;
72       *activation_max = qmax;
73       break;
74     case Activation::RELU:
75       *activation_min = std::max(qmin, quantize(0.0f));
76       *activation_max = qmax;
77       break;
78     case Activation::RELU_N1_TO_1:
79       *activation_min = std::max(qmin, quantize(-1.0f));
80       *activation_max = std::min(qmax, quantize(1.0f));
81       break;
82     case Activation::RELU6:
83       *activation_min = std::max(qmin, quantize(0.0f));
84       *activation_max = std::min(qmax, quantize(6.0f));
85       break;
86     default:
87       throw std::runtime_error("Unsupported activation.");
88   }
89 }
90
91 void calculateActivationRangeQuantized(Activation activation, const Tensor *output,
92                                        int32_t *activation_min, int32_t *activation_max)
93 {
94   assert(output->zero_points().size() == 1);
95   int32_t qmin{};
96   int32_t qmax{};
97   switch (output->element_type())
98   {
99     case DataType::U8:
100       qmin = 0;
101       qmax = std::numeric_limits<uint8_t>::max();
102       break;
103     case DataType::S8:
104       qmin = -std::numeric_limits<int8_t>::max();
105       qmax = std::numeric_limits<int8_t>::max();
106       break;
107     case DataType::S16:
108       // For now, assume that signed int16 type implies signed symmetric quantization.
109       assert(output->zero_point() == 0);
110       qmin = -std::numeric_limits<int16_t>::max();
111       qmax = std::numeric_limits<int16_t>::max();
112       break;
113     default:
114       throw std::runtime_error("Unsupported type.");
115   }
116
117   calculateActivationRangeQuantizedImpl(activation, qmin, qmax, output, activation_min,
118                                         activation_max);
119 }
120
121 void quantizeMultiplier(double double_multiplier, int32_t *quantized_multiplier, int *shift)
122 {
123   if (double_multiplier == 0.0)
124   {
125     *quantized_multiplier = 0;
126     *shift = 0;
127     return;
128   }
129
130   const double q = std::frexp(double_multiplier, shift);
131   auto q_fixed = static_cast<int64_t>(std::round(q * (INT64_C(1) << 31)));
132
133   if (q_fixed == (INT64_C(1) << 31))
134   {
135     q_fixed /= 2;
136     ++*shift;
137   }
138   assert(q_fixed <= std::numeric_limits<int32_t>::max());
139   // A shift amount smaller than -31 would cause all bits to be shifted out
140   // and thus all results would be zero. We implement that instead with
141   // q_fixed==0, so as to avoid hitting issues with right-shift
142   // operations with shift amounts greater than 31. Note that this happens
143   // roughly when abs(double_multiplier) < 2^-31 and the present handling means
144   // that we're effectively flushing tiny double_multiplier's to zero.
145   // We could conceivably handle values in the range (roughly) [32, 63]
146   // as 'denormals' i.e. (shift==0, q_fixed < 2^30). In that point of view
147   // the present handling is just doing 'flush denormals to zero'. We could
148   // reconsider and actually generate nonzero denormals if a need arises.
149   if (*shift < -31)
150   {
151     *shift = 0;
152     q_fixed = 0;
153   }
154   *quantized_multiplier = static_cast<int32_t>(q_fixed);
155 }
156
157 void quantizeMultiplierSmallerThanOneExp(double double_multiplier, int32_t *quantized_multiplier,
158                                          int *left_shift)
159 {
160   assert(double_multiplier < 1.0);
161   assert(double_multiplier > 0.0);
162   int shift;
163   quantizeMultiplier(double_multiplier, quantized_multiplier, &shift);
164   assert(shift <= 0);
165   *left_shift = shift;
166 }
167
168 Shape calculateShapeForBroadcast(const Shape &input1_shape, const Shape &input2_shape)
169 {
170   const int num_input1_dims = input1_shape.num_dims();
171   const int num_input2_dims = input2_shape.num_dims();
172   const int num_out_dims = std::max(num_input1_dims, num_input2_dims);
173   Shape output_shape(num_out_dims);
174
175   for (int i = 0; i < num_out_dims; ++i)
176   {
177     const int32_t input1_dim = i < num_input1_dims ? input1_shape.dim(num_input1_dims - i - 1) : 1;
178     const int32_t input2_dim = i < num_input2_dims ? input2_shape.dim(num_input2_dims - i - 1) : 1;
179     assert(input1_dim == input2_dim || input1_dim == 1 || input2_dim == 1);
180     output_shape.dim(num_out_dims - i - 1) = std::max(input1_dim, input2_dim);
181   }
182
183   return output_shape;
184 }
185
186 } // namespace kernels
187 } // namespace luci_interpreter