Imported Upstream version 1.19.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       *activation_min = std::numeric_limits<float>::lowest();
36       *activation_max = std::numeric_limits<float>::max();
37       break;
38     case Activation::RELU:
39       *activation_min = 0;
40       *activation_max = std::numeric_limits<float>::max();
41       break;
42     case Activation::RELU_N1_TO_1:
43       *activation_min = -1;
44       *activation_max = 1;
45       break;
46     case Activation::RELU6:
47       *activation_min = 0;
48       *activation_max = 6;
49       break;
50     default:
51       throw std::runtime_error("Unsupported activation.");
52   }
53 }
54
55 static void calculateActivationRangeQuantizedImpl(Activation activation, int32_t qmin, int32_t qmax,
56                                                   const Tensor *output, int32_t *activation_min,
57                                                   int32_t *activation_max)
58 {
59   const float scale = output->scale();
60   const int32_t zero_point = output->zero_point();
61
62   auto quantize = [scale, zero_point](float x) {
63     return zero_point + static_cast<int32_t>(std::round(x / scale));
64   };
65
66   switch (activation)
67   {
68     case Activation::NONE:
69     case Activation::TANH:
70       *activation_min = qmin;
71       *activation_max = qmax;
72       break;
73     case Activation::RELU:
74       *activation_min = std::max(qmin, quantize(0.0f));
75       *activation_max = qmax;
76       break;
77     case Activation::RELU_N1_TO_1:
78       *activation_min = std::max(qmin, quantize(-1.0f));
79       *activation_max = std::min(qmax, quantize(1.0f));
80       break;
81     case Activation::RELU6:
82       *activation_min = std::max(qmin, quantize(0.0f));
83       *activation_max = std::min(qmax, quantize(6.0f));
84       break;
85     default:
86       throw std::runtime_error("Unsupported activation.");
87   }
88 }
89
90 void calculateActivationRangeQuantized(Activation activation, const Tensor *output,
91                                        int32_t *activation_min, int32_t *activation_max)
92 {
93   assert(output->zero_points().size() == 1);
94   int32_t qmin{};
95   int32_t qmax{};
96   switch (output->element_type())
97   {
98     case DataType::U8:
99       qmin = 0;
100       qmax = std::numeric_limits<uint8_t>::max();
101       break;
102     case DataType::S8:
103       qmin = -std::numeric_limits<int8_t>::max();
104       qmax = std::numeric_limits<int8_t>::max();
105       break;
106     case DataType::S16:
107       // For now, assume that signed int16 type implies signed symmetric quantization.
108       assert(output->zero_point() == 0);
109       qmin = -std::numeric_limits<int16_t>::max();
110       qmax = std::numeric_limits<int16_t>::max();
111       break;
112     default:
113       throw std::runtime_error("Unsupported type.");
114   }
115
116   calculateActivationRangeQuantizedImpl(activation, qmin, qmax, output, activation_min,
117                                         activation_max);
118 }
119
120 void quantizeMultiplier(double double_multiplier, int32_t *quantized_multiplier, int *shift)
121 {
122   if (double_multiplier == 0.0)
123   {
124     *quantized_multiplier = 0;
125     *shift = 0;
126     return;
127   }
128
129   const double q = std::frexp(double_multiplier, shift);
130   auto q_fixed = static_cast<int64_t>(std::round(q * (INT64_C(1) << 31)));
131
132   if (q_fixed == (INT64_C(1) << 31))
133   {
134     q_fixed /= 2;
135     ++*shift;
136   }
137   assert(q_fixed <= std::numeric_limits<int32_t>::max());
138   // A shift amount smaller than -31 would cause all bits to be shifted out
139   // and thus all results would be zero. We implement that instead with
140   // q_fixed==0, so as to avoid hitting issues with right-shift
141   // operations with shift amounts greater than 31. Note that this happens
142   // roughly when abs(double_multiplier) < 2^-31 and the present handling means
143   // that we're effectively flushing tiny double_multiplier's to zero.
144   // We could conceivably handle values in the range (roughly) [32, 63]
145   // as 'denormals' i.e. (shift==0, q_fixed < 2^30). In that point of view
146   // the present handling is just doing 'flush denormals to zero'. We could
147   // reconsider and actually generate nonzero denormals if a need arises.
148   if (*shift < -31)
149   {
150     *shift = 0;
151     q_fixed = 0;
152   }
153   *quantized_multiplier = static_cast<int32_t>(q_fixed);
154 }
155
156 void quantizeMultiplierSmallerThanOneExp(double double_multiplier, int32_t *quantized_multiplier,
157                                          int *left_shift)
158 {
159   assert(double_multiplier < 1.0);
160   assert(double_multiplier > 0.0);
161   int shift;
162   quantizeMultiplier(double_multiplier, quantized_multiplier, &shift);
163   assert(shift <= 0);
164   *left_shift = shift;
165 }
166
167 Shape calculateShapeForBroadcast(const Shape &input1_shape, const Shape &input2_shape)
168 {
169   const int num_input1_dims = input1_shape.num_dims();
170   const int num_input2_dims = input2_shape.num_dims();
171   const int num_out_dims = std::max(num_input1_dims, num_input2_dims);
172   Shape output_shape(num_out_dims);
173
174   for (int i = 0; i < num_out_dims; ++i)
175   {
176     const int32_t input1_dim = i < num_input1_dims ? input1_shape.dim(num_input1_dims - i - 1) : 1;
177     const int32_t input2_dim = i < num_input2_dims ? input2_shape.dim(num_input2_dims - i - 1) : 1;
178     assert(input1_dim == input2_dim || input1_dim == 1 || input2_dim == 1);
179     output_shape.dim(num_out_dims - i - 1) = std::max(input1_dim, input2_dim);
180   }
181
182   return output_shape;
183 }
184
185 } // namespace kernels
186 } // namespace luci_interpreter