ONE - On-device Neural Engine
Loading...
Searching...
No Matches
BinaryOpCommon.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_BINARYOPUTILS_H
19#define LUCI_INTERPRETER_KERNELS_BINARYOPUTILS_H
20
21#include "TISOKernel.h"
22#include "PALComparisons.h"
23#include "Params.h"
24#include "ProcessBroadcastShapes.h"
25#include "Utils.h"
26
27namespace luci_interpreter
28{
29namespace kernels
30{
31
32namespace
33{
34
44template <typename T>
46{
47 static_assert(one_of_types<T, float, int32_t, int64_t>(), "Unsupported dtype");
48
49 if (std::is_same<T, float>::value)
51 if (std::is_same<T, int32_t>::value)
53 else
55}
56
57} // namespace
58
59template <typename T, typename TISOFunc = nullptr_t, typename TISOBroadcastFunc = nullptr_t,
60 typename Options = nullptr_t>
61void evalTISOKernel(TISOFunc tiso_func, TISOBroadcastFunc tiso_broadcast_func,
62 kernels::TISOKernel *kernel, kernels::TISOData *kernel_data,
63 const Options *options, RuntimeShape &&input_shape_1,
64 RuntimeShape &&input_shape_2, RuntimeShape &&output_shape)
65{
67 fillArithmeticActivationRange<T>(params, luci_actfunc(options->fused_activation_function()));
68
69 const bool need_broadcast =
70 luci_interpreter_pal::ProcessBroadcastShapes(input_shape_1, input_shape_2, &params);
71
72 if (need_broadcast)
73 {
74 tiso_broadcast_func(params, input_shape_1, kernels::getTensorData<T>(kernel_data->input1_data),
75 input_shape_2, kernels::getTensorData<T>(kernel_data->input2_data),
76 output_shape, kernels::getTensorData<T>(kernel_data->output_data));
77 }
78 else
79 {
80 const int flat_size = input_shape_1.flatSize();
81 tiso_func(params, flat_size, kernels::getTensorData<T>(kernel_data->input1_data),
82 kernels::getTensorData<T>(kernel_data->input2_data),
83 kernels::getTensorData<T>(kernel_data->output_data));
84 }
85}
86
87template <typename T, typename TISOFunc = nullptr_t, typename TISOBroadcastFunc = nullptr_t,
88 typename Options = nullptr_t>
89void evalTISOInplaceKernel(TISOFunc tiso_func, TISOBroadcastFunc tiso_broadcast_func,
90 kernels::TISOKernel *kernel, const Options *options,
91 RuntimeShape &&input_shape_1, RuntimeShape &&input_shape_2,
93{
94 uint8_t *inplace_data_ptr = nullptr;
95 circle::Tensor *input_inplace_tensor = nullptr;
96
97 kernels::TISOData kernel_data = kernel->readInplaceData(inplace_data_ptr, input_inplace_tensor);
98
99 evalTISOKernel<T, TISOFunc, TISOBroadcastFunc, Options>(
100 tiso_func, tiso_broadcast_func, kernel, &kernel_data, options, std::move(input_shape_1),
101 std::move(input_shape_2), std::move(output_shape));
102
103 BaseRuntimeGraph *runtime_graph = kernel->runtime_graph();
104
105 runtime_graph->makeInplaceOperation(input_inplace_tensor, kernel->output());
106 if (input_inplace_tensor == kernel->input1())
107 {
108 runtime_graph->makeInplaceOperation(kernel->input2(), nullptr);
109 }
110 else
111 {
112 runtime_graph->makeInplaceOperation(kernel->input1(), nullptr);
113 }
114}
115
117{
118 LUCI_INTERPRETER_CHECK(Tensor::element_type(kernel.input1()) ==
119 Tensor::element_type(kernel.input2()));
120 LUCI_INTERPRETER_CHECK(Tensor::element_type(kernel.input1()) ==
121 Tensor::element_type(kernel.output()));
122}
123
124#ifndef DIS_QUANT
125template <typename T, typename TISOFunc = nullptr_t, typename TISOBroadcastFunc = nullptr_t,
126 typename Options = nullptr_t>
127void evalTISOQuantizedKernel(TISOFunc tiso_func, TISOBroadcastFunc tiso_broadcast_func,
128 kernels::TISOKernel *kernel, kernels::TISOData *kernel_data,
129 const Options *options)
130{
131 const auto *input1 = kernel->input1();
132 const auto *input2 = kernel->input2();
133 const auto *output = kernel->output();
134
135 const auto input1_scale = static_cast<double>(Tensor::scale(input1));
136 const auto input2_scale = static_cast<double>(Tensor::scale(input2));
137 const auto output_scale = static_cast<double>(Tensor::scale(output));
138
139 const int left_shift = 20;
140 const double twice_max_input_scale = 2 * std::max(input1_scale, input2_scale);
141 const double real_input1_multiplier = input1_scale / twice_max_input_scale;
142 const double real_input2_multiplier = input2_scale / twice_max_input_scale;
143 const double real_output_multiplier = twice_max_input_scale / ((1 << left_shift) * output_scale);
144
145 int32_t input1_multiplier{}, input2_multiplier{}, output_multiplier{};
146 int input1_shift{}, input2_shift{}, output_shift{};
147 kernels::quantizeMultiplierSmallerThanOneExp(real_input1_multiplier, &input1_multiplier,
148 &input1_shift);
149 kernels::quantizeMultiplierSmallerThanOneExp(real_input2_multiplier, &input2_multiplier,
150 &input2_shift);
151 kernels::quantizeMultiplierSmallerThanOneExp(real_output_multiplier, &output_multiplier,
152 &output_shift);
153
154 int32_t activation_min{};
155 int32_t activation_max{};
156 kernels::calculateActivationRangeQuantized(luci_actfunc(options->fused_activation_function()),
157 output, &activation_min, &activation_max);
158
160 params.left_shift = left_shift;
161 // The kernel expects inputs' zero points to be negated.
162 params.input1_offset = -Tensor::zero_point(input1); // Note the '-'.
163 params.input1_multiplier = input1_multiplier;
164 params.input1_shift = input1_shift;
165 params.input2_offset = -Tensor::zero_point(input2); // Note the '-'.
166 params.input2_multiplier = input2_multiplier;
167 params.input2_shift = input2_shift;
168 params.output_offset = Tensor::zero_point(output);
169 params.output_multiplier = output_multiplier;
170 params.output_shift = output_shift;
171 params.quantized_activation_min = activation_min;
172 params.quantized_activation_max = activation_max;
173
174 const bool need_broadcast = luci_interpreter_pal::ProcessBroadcastShapes(
175 kernels::getTensorShape(input1), kernels::getTensorShape(input2), &params);
176
177 if (need_broadcast)
178 {
179 tiso_broadcast_func(
180 params, kernels::getTensorShape(input1), kernels::getTensorData<T>(kernel_data->input1_data),
181 kernels::getTensorShape(input2), kernels::getTensorData<T>(kernel_data->input2_data),
182 kernels::getTensorShape(output), kernels::getTensorData<T>(kernel_data->output_data));
183 }
184 else
185 {
186 tiso_func(params, kernels::getTensorShape(input1),
187 kernels::getTensorData<uint8_t>(kernel_data->input1_data),
188 kernels::getTensorShape(input2), kernels::getTensorData<T>(kernel_data->input2_data),
189 kernels::getTensorShape(output), kernels::getTensorData<T>(kernel_data->output_data));
190 }
191}
192
193template <typename T, typename TISOFunc = nullptr_t, typename TISOBroadcastFunc = nullptr_t,
194 typename Options = nullptr_t>
195void evalTISOInplaceQuantizedKernel(TISOFunc tiso_func, TISOBroadcastFunc tiso_broadcast_func,
196 kernels::TISOKernel *kernel, const Options *options)
197{
198 uint8_t *inplace_data_ptr = nullptr;
199 circle::Tensor *input_inplace_tensor = nullptr;
200
201 kernels::TISOData kernel_data = kernel->readInplaceData(inplace_data_ptr, input_inplace_tensor);
202
203 evalTISOQuantizedKernel<T, TISOFunc, TISOBroadcastFunc, Options>(tiso_func, tiso_broadcast_func,
204 kernel, &kernel_data, options);
205
206 kernel->runtime_graph()->makeInplaceOperation(input_inplace_tensor, kernel->output());
207 if (input_inplace_tensor == kernel->input1())
208 {
209 kernel->runtime_graph()->makeInplaceOperation(kernel->input2(), nullptr);
210 }
211 else
212 {
213 kernel->runtime_graph()->makeInplaceOperation(kernel->input1(), nullptr);
214 }
215}
216
217#endif // DIS_QUANT
218
219} // namespace kernels
220} // namespace luci_interpreter
221
222#endif // LUCI_INTERPRETER_KERNELS_BINARYOPUTILS_H
void makeInplaceOperation(const circle::Tensor *src_tensor, const circle::Tensor *dst_tensor)
BaseRuntimeGraph * runtime_graph() const
Definition TISOKernel.h:64
TISOData readInplaceData(uint8_t *&inplace_data_ptr, circle::Tensor *&input_inplace_tensor)
Definition TISOKernel.h:84
const circle::Tensor * output() const
Definition TISOKernel.h:62
const circle::Tensor * input2() const
Definition TISOKernel.h:61
const circle::Tensor * input1() const
Definition TISOKernel.h:60
#define LUCI_INTERPRETER_CHECK(cond)
Definition Utils.h:36
const luci_interpreter::RuntimeShape output_shape
void evalTISOInplaceKernel(TISOFunc tiso_func, TISOBroadcastFunc tiso_broadcast_func, kernels::TISOKernel *kernel, const Options *options, RuntimeShape &&input_shape_1, RuntimeShape &&input_shape_2, RuntimeShape &&output_shape)
void evalTISOQuantizedKernel(TISOFunc tiso_func, TISOBroadcastFunc tiso_broadcast_func, kernels::TISOKernel *kernel, kernels::TISOData *kernel_data, const Options *options)
void evalTISOKernel(TISOFunc tiso_func, TISOBroadcastFunc tiso_broadcast_func, kernels::TISOKernel *kernel, kernels::TISOData *kernel_data, const Options *options, RuntimeShape &&input_shape_1, RuntimeShape &&input_shape_2, RuntimeShape &&output_shape)
tflite::RuntimeShape getTensorShape(const Tensor *tensor)
Definition Utils.h:194
luci_interpreter::FusedActFunc Activation
Definition Utils.h:34
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
void CheckBinaryOpDataTypesEqual(const kernels::TISOKernel &kernel)
void evalTISOInplaceQuantizedKernel(TISOFunc tiso_func, TISOBroadcastFunc tiso_broadcast_func, kernels::TISOKernel *kernel, const Options *options)
void fillArithmeticActivationRange(tflite::ArithmeticParams &p, Activation act)
Definition Utils.h:106
bool ProcessBroadcastShapes(const luci_interpreter::RuntimeShape &shape0, const luci_interpreter::RuntimeShape &shape1, luci_interpreter_pal::ArithmeticParams *params)
FusedActFunc luci_actfunc(const circle::ActivationFunctionType type)
This file contains utility macro.