ONE - On-device Neural Engine
Loading...
Searching...
No Matches
Utils.h
Go to the documentation of this file.
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#ifndef LUCI_INTERPRETER_KERNELS_UTILS_H
19#define LUCI_INTERPRETER_KERNELS_UTILS_H
20
21#include "core/KernelParams.h"
22#include "luci_interpreter/core/Tensor.h"
23
24#include <tensorflow/lite/kernels/internal/tensor_utils.h>
25#include <tensorflow/lite/kernels/internal/types.h>
26
27#include <cassert>
28#include <cstdint>
29#include <stdexcept>
30
31namespace luci_interpreter
32{
33namespace kernels
34{
35
36#define LUCI_INTERPRETER_CHECK(cond) \
37 if (!(cond)) \
38 throw std::runtime_error(std::string(__FILE__) + ":" + std::to_string(__LINE__) + +"(" + \
39 std::string(#cond) + ") was not true.");
40
41inline int32_t computePadding(int32_t stride, int32_t dilation_rate, int32_t in_size,
42 int32_t filter_size, int32_t out_size)
43{
44 const int32_t effective_filter_size = (filter_size - 1) * dilation_rate + 1;
45 const int32_t padding = ((out_size - 1) * stride + effective_filter_size - in_size) / 2;
46 return padding > 0 ? padding : 0;
47}
48
49inline int32_t computePaddingWithOffset(int32_t stride, int32_t dilation_rate, int32_t in_size,
50 int32_t filter_size, int32_t out_size, int32_t *offset)
51{
52 int32_t effective_filter_size = (filter_size - 1) * dilation_rate + 1;
53 int32_t total_padding = ((out_size - 1) * stride + effective_filter_size - in_size);
54 total_padding = total_padding > 0 ? total_padding : 0;
55 *offset = total_padding % 2;
56 return total_padding / 2;
57}
58
59inline int32_t computeOutputSize(Padding padding, int32_t image_size, int32_t filter_size,
60 int32_t stride, int32_t dilation_rate = 1)
61{
62 const int32_t effective_filter_size = (filter_size - 1) * dilation_rate + 1;
63 switch (padding)
64 {
65 case Padding::SAME:
66 return (image_size + stride - 1) / stride;
67 case Padding::VALID:
68 return (image_size + stride - effective_filter_size) / stride;
69 default:
70 assert(false);
71 return 0;
72 }
73}
74
75inline int32_t calcOffset(const Shape &shape, int32_t d0, int32_t d1, int32_t d2, int32_t d3)
76{
77 return ((d0 * shape.dim(1) + d1) * shape.dim(2) + d2) * shape.dim(3) + d3;
78}
79
80TfLiteFusedActivation getTfLiteActivation(Activation activation);
81
82template <typename T>
83void calculateActivationRange(Activation activation, T *activation_min, T *activation_max);
84
85void calculateActivationRangeQuantized(Activation activation, const Tensor *output,
86 int32_t *activation_min, int32_t *activation_max);
87
88template <typename T> constexpr bool one_of_types() { return false; }
89
90// Checks if T is equal to one of {U,Other} types
91template <typename T, typename U, typename... Other> constexpr bool one_of_types()
92{
93 return std::is_same<T, U>::value || one_of_types<T, Other...>();
94}
95
105template <typename T>
106void fillArithmeticActivationRange(tflite::ArithmeticParams &p, Activation act)
107{
108 static_assert(one_of_types<T, float, int32_t, int64_t>(), "Unsupported dtype");
109
110 if (std::is_same<T, float>::value)
111 calculateActivationRange(act, &p.float_activation_min, &p.float_activation_max);
112 if (std::is_same<T, int32_t>::value)
113 calculateActivationRange(act, &p.quantized_activation_min, &p.quantized_activation_max);
114 else
115 calculateActivationRange(act, &p.int64_activation_min, &p.int64_activation_max);
116}
117
118// Decompose a double multiplier into a Q0.31 int32 representation of its
119// significand, and shift representation of its exponent.
120//
121// Handles an arbitrary positive multiplier. The 'shift' output-value is
122// basically the 'floating-point exponent' of the multiplier:
123// Negative for a right-shift (when the multiplier is <1), positive for a
124// left-shift (when the multiplier is >1)
125void quantizeMultiplier(double double_multiplier, int32_t *quantized_multiplier, int *shift);
126
127// Decompose a double multiplier into a Q0.31 int32 representation of its
128// significand, and shift representation of NEGATIVE its exponent ---
129// this is intended as a RIGHT-shift.
130//
131// Restricted to the case where the multiplier < 1 (and non-negative).
132void quantizeMultiplierSmallerThanOneExp(double double_multiplier, int32_t *quantized_multiplier,
133 int *left_shift);
134
135Shape calculateShapeForBroadcast(const Shape &input1_shape, const Shape &input2_shape);
136
137inline double getQuantizedConvolutionMultipler(float input_scale, float filter_scale,
138 float output_scale)
139{
140 const double input_product_scale = static_cast<double>(input_scale * filter_scale);
141 LUCI_INTERPRETER_CHECK(input_product_scale >= 0);
142 return input_product_scale / static_cast<double>(output_scale);
143}
144
145// TODO rename getQuantizedConvolutionMultiplers to something more general
146// it is used for non conv operators too
147inline std::vector<double> getQuantizedConvolutionMultiplers(float input_scale,
148 const std::vector<float> &filter_scale,
149 float output_scale)
150{
151 std::vector<double> effective_output_scales;
152 size_t n = filter_scale.size();
153 effective_output_scales.reserve(n);
154 for (size_t i = 0; i < n; ++i)
155 {
156 effective_output_scales.push_back(
157 getQuantizedConvolutionMultipler(input_scale, filter_scale[i], output_scale));
158 }
159 return effective_output_scales;
160}
161
168
169inline std::vector<ChannelQuantMultipliers>
170quantizeMultipliers(const std::vector<double> &effective_scale)
171{
172 size_t n = effective_scale.size();
173 std::vector<ChannelQuantMultipliers> params(n);
174 for (size_t i = 0; i < n; ++i)
175 {
176 quantizeMultiplier(effective_scale[i], &params[i].multiplier, &params[i].shift);
177 }
178 return params;
179}
180
181// Helper wrapper to hide broadcast logic
182template <typename T> class BroadcastableWrapper
183{
184public:
185 BroadcastableWrapper(const std::vector<T> &v) : _v(v), _stride(v.size() == 1 ? 0 : 1) {}
186
187 T operator[](int idx) { return _v[idx * _stride]; }
188
189private:
190 const std::vector<T> &_v;
191 int _stride;
192};
193
194inline tflite::RuntimeShape getTensorShape(const Tensor *tensor)
195{
196 if (tensor == nullptr)
197 return tflite::RuntimeShape();
198
199 const Shape &shape = tensor->shape();
200 tflite::RuntimeShape runtime_shape(shape.num_dims());
201 for (int i = 0; i < shape.num_dims(); ++i)
202 {
203 runtime_shape.SetDim(i, shape.dim(i));
204 }
205 return runtime_shape;
206}
207
208template <typename T> const T *getTensorData(const Tensor *tensor)
209{
210 return tensor != nullptr ? tensor->data<T>() : nullptr;
211}
212
213template <typename T> T *getTensorData(Tensor *tensor)
214{
215 return tensor != nullptr ? tensor->data<T>() : nullptr;
216}
217
218// A list of tensors in a format that can be used by kernels like split and
219// concatenation.
220template <typename T, bool is_const> class VectorOfTensors
221{
222public:
223 using ElementT = typename std::conditional<is_const, const T, T>::type;
224 using TensorT = typename std::conditional<is_const, const Tensor, Tensor>::type;
225
226 // Build with the tensors in 'tensor_list'.
227 explicit VectorOfTensors(const std::vector<TensorT *> &tensor_list)
228 {
229 const int num_tensors = tensor_list.size();
230
231 all_data_.reserve(num_tensors);
232 all_shape_.reserve(num_tensors);
233 all_shape_ptr_.reserve(num_tensors);
234
235 for (TensorT *tensor : tensor_list)
236 {
237 all_data_.push_back(getTensorData<T>(tensor));
238 all_shape_.push_back(getTensorShape(tensor));
239 }
240
241 // Taking the pointer from inside a std::vector is only OK if the vector is
242 // never modified, so we populate all_shape in the previous loop and then we
243 // are free to grab iterators here.
244 for (tflite::RuntimeShape &shape : all_shape_)
245 {
246 all_shape_ptr_.push_back(&shape);
247 }
248 }
249 // Return a pointer to the data pointers of all tensors in the list. For
250 // example:
251 // float* const* f = v.data();
252 // f[0][1] is the second element of the first tensor.
253 ElementT *const *data() const { return all_data_.data(); }
254
255 // Return a pointer the shape pointers of all tensors in the list. For
256 // example:
257 // const RuntimeShape* const* d = v.dims();
258 // dims[1] are the dimensions of the second tensor in the list.
259 const tflite::RuntimeShape *const *shapes() const { return all_shape_ptr_.data(); }
260
261private:
262 std::vector<ElementT *> all_data_;
263 std::vector<tflite::RuntimeShape> all_shape_;
264 std::vector<tflite::RuntimeShape *> all_shape_ptr_;
265};
266
267// A list of quantized tensors in a format that can be used by kernels like
268// split and concatenation.
269template <bool is_const> class VectorOfQuantizedTensors : public VectorOfTensors<uint8_t, is_const>
270{
271public:
273
274 // Build with the tensors in 'tensor_list'.
275 explicit VectorOfQuantizedTensors(const std::vector<TensorT *> &tensor_list)
276 : VectorOfTensors<uint8_t, is_const>(tensor_list)
277 {
278 for (TensorT *tensor : tensor_list)
279 {
280 zero_point_.push_back(tensor->zero_point());
281 scale_.push_back(tensor->scale());
282 }
283 }
284
285 const float *scale() const { return scale_.data(); }
286 const int32_t *zero_point() const { return zero_point_.data(); }
287
288private:
289 std::vector<int32_t> zero_point_;
290 std::vector<float> scale_;
291};
292
293} // namespace kernels
294} // namespace luci_interpreter
295
296#endif // LUCI_INTERPRETER_KERNELS_UTILS_H
int32_t dim(int i) const
Definition Tensor.h:41
int num_dims() const
Definition Tensor.h:39
BroadcastableWrapper(const std::vector< T > &v)
Definition Utils.h:185
VectorOfQuantizedTensors(const std::vector< TensorT * > &tensor_list)
Definition Utils.h:275
VectorOfTensors(const std::vector< TensorT * > &tensor_list)
Definition Utils.h:227
const tflite::RuntimeShape *const * shapes() const
Definition Utils.h:259
ElementT *const * data() const
Definition Utils.h:253
typename std::conditional< is_const, const Tensor, Tensor >::type TensorT
Definition Utils.h:224
typename std::conditional< is_const, const T, T >::type ElementT
Definition Utils.h:223
#define LUCI_INTERPRETER_CHECK(cond)
Definition Utils.h:36
__global uchar * offset(const Image *img, int x, int y)
Definition helpers.h:540
int32_t computePadding(int32_t stride, int32_t dilation_rate, int32_t in_size, int32_t filter_size, int32_t out_size)
Definition Utils.h:41
int32_t calcOffset(const Shape &shape, int32_t d0, int32_t d1, int32_t d2, int32_t d3)
Definition Utils.h:75
Shape calculateShapeForBroadcast(const Shape &input1_shape, const Shape &input2_shape)
Definition Utils.cpp:204
TfLiteFusedActivation getTfLiteActivation(Activation activation)
Definition Utils.cpp:30
const T * getTensorData(const Tensor *tensor)
Definition Utils.h:208
std::vector< ChannelQuantMultipliers > quantizeMultipliers(const std::vector< double > &effective_scale)
Definition Utils.h:170
tflite::RuntimeShape getTensorShape(const Tensor *tensor)
Definition Utils.h:194
void calculateActivationRange(Activation activation, T *activation_min, T *activation_max)
Definition Utils.cpp:52
void quantizeMultiplierSmallerThanOneExp(double double_multiplier, int32_t *quantized_multiplier, int *left_shift)
Definition Utils.cpp:193
void calculateActivationRangeQuantized(Activation activation, const Tensor *output, int32_t *activation_min, int32_t *activation_max)
Definition Utils.cpp:119
constexpr bool one_of_types()
Definition Utils.h:88
double getQuantizedConvolutionMultipler(float input_scale, float filter_scale, float output_scale)
Definition Utils.h:137
int32_t computePaddingWithOffset(int32_t stride, int32_t dilation_rate, int32_t in_size, int32_t filter_size, int32_t out_size, int32_t *offset)
Definition Utils.h:49
void quantizeMultiplier(double double_multiplier, int32_t *quantized_multiplier, int *shift)
Definition Utils.cpp:157
int32_t computeOutputSize(Padding padding, int32_t image_size, int32_t filter_size, int32_t stride, int32_t dilation_rate=1)
Definition Utils.h:59
std::vector< double > getQuantizedConvolutionMultiplers(float input_scale, const std::vector< float > &filter_scale, float output_scale)
Definition Utils.h:147
void fillArithmeticActivationRange(tflite::ArithmeticParams &p, Activation act)
Definition Utils.h:106
int32_t size[5]
Definition Slice.cpp:35