2 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
3 * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "kernels/Utils.h"
25 namespace luci_interpreter
30 void calculateActivationRange(Activation activation, float *activation_min, float *activation_max)
34 case Activation::NONE:
35 *activation_min = std::numeric_limits<float>::lowest();
36 *activation_max = std::numeric_limits<float>::max();
38 case Activation::RELU:
40 *activation_max = std::numeric_limits<float>::max();
42 case Activation::RELU_N1_TO_1:
46 case Activation::RELU6:
51 throw std::runtime_error("Unsupported activation.");
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)
59 const float scale = output->scale();
60 const int32_t zero_point = output->zero_point();
62 auto quantize = [scale, zero_point](float x) {
63 return zero_point + static_cast<int32_t>(std::round(x / scale));
68 case Activation::NONE:
69 case Activation::TANH:
70 *activation_min = qmin;
71 *activation_max = qmax;
73 case Activation::RELU:
74 *activation_min = std::max(qmin, quantize(0.0f));
75 *activation_max = qmax;
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));
81 case Activation::RELU6:
82 *activation_min = std::max(qmin, quantize(0.0f));
83 *activation_max = std::min(qmax, quantize(6.0f));
86 throw std::runtime_error("Unsupported activation.");
90 void calculateActivationRangeQuantized(Activation activation, const Tensor *output,
91 int32_t *activation_min, int32_t *activation_max)
93 assert(output->zero_points().size() == 1);
96 switch (output->element_type())
100 qmax = std::numeric_limits<uint8_t>::max();
103 qmin = -std::numeric_limits<int8_t>::max();
104 qmax = std::numeric_limits<int8_t>::max();
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();
113 throw std::runtime_error("Unsupported type.");
116 calculateActivationRangeQuantizedImpl(activation, qmin, qmax, output, activation_min,
120 void quantizeMultiplier(double double_multiplier, int32_t *quantized_multiplier, int *shift)
122 if (double_multiplier == 0.0)
124 *quantized_multiplier = 0;
129 const double q = std::frexp(double_multiplier, shift);
130 auto q_fixed = static_cast<int64_t>(std::round(q * (INT64_C(1) << 31)));
132 if (q_fixed == (INT64_C(1) << 31))
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.
153 *quantized_multiplier = static_cast<int32_t>(q_fixed);
156 void quantizeMultiplierSmallerThanOneExp(double double_multiplier, int32_t *quantized_multiplier,
159 assert(double_multiplier < 1.0);
160 assert(double_multiplier > 0.0);
162 quantizeMultiplier(double_multiplier, quantized_multiplier, &shift);
167 Shape calculateShapeForBroadcast(const Shape &input1_shape, const Shape &input2_shape)
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);
174 for (int i = 0; i < num_out_dims; ++i)
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);
185 } // namespace kernels
186 } // namespace luci_interpreter