f6b521db3c7dec18861f1bf94093e41cd6767ae8
[platform/core/ml/nnfw.git] / onert-micro / luci-interpreter / src / kernels / MaxPool2D.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
3  * Copyright 2019 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 "Builders.h"
19
20 #include "kernels/Utils.h"
21
22 #include <tensorflow/lite/kernels/internal/reference/integer_ops/pooling.h>
23 #include <tensorflow/lite/kernels/internal/reference/pooling.h>
24
25 namespace luci_interpreter
26 {
27
28 namespace
29 {
30
31 #ifndef DIS_FLOAT
32
33 void evalFloat(const circle::Tensor *input, const circle::Tensor *output,
34                const circle::Pool2DOptions *options, BaseRuntimeGraph *runtime_graph)
35 {
36   const int32_t input_height = Tensor::dim(input, 1);
37   const int32_t input_width = Tensor::dim(input, 2);
38
39   const int32_t output_height = kernels::computeOutputSize(
40     luci_padding(options->padding()), input_height, options->filter_height(), options->stride_h());
41   const int32_t output_width = kernels::computeOutputSize(
42     luci_padding(options->padding()), input_width, options->filter_width(), options->stride_w());
43
44   const auto padding_height = kernels::computePadding(options->stride_h(), 1, input_height,
45                                                       options->filter_height(), output_height);
46   const auto padding_width = kernels::computePadding(options->stride_w(), 1, input_width,
47                                                      options->filter_width(), output_width);
48
49   const auto *input_data = runtime_graph->getDataByTensor(input);
50   auto *output_data = runtime_graph->getDataByTensor(output);
51
52   float activation_min{};
53   float activation_max{};
54   kernels::calculateActivationRange(luci_actfunc(options->fused_activation_function()),
55                                     &activation_min, &activation_max);
56   tflite::PoolParams params{};
57   params.padding_values.height = padding_height;
58   params.padding_values.width = padding_width;
59   params.stride_height = options->stride_h();
60   params.stride_width = options->stride_w();
61   params.filter_height = options->filter_height();
62   params.filter_width = options->filter_width();
63   params.float_activation_min = activation_min;
64   params.float_activation_max = activation_max;
65
66   tflite::reference_ops::MaxPool(
67     params, kernels::getTensorShape(input), kernels::getTensorData<float>(input_data),
68     kernels::getTensorShape(output), kernels::getTensorData<float>(output_data));
69 }
70
71 #endif // DIS_FLOAT
72
73 #ifndef DIS_QUANT
74 void evalQuantized(const circle::Tensor *input, const circle::Tensor *output,
75                    const circle::Pool2DOptions *options, BaseRuntimeGraph *runtime_graph)
76 {
77   int32_t activation_min{};
78   int32_t activation_max{};
79   kernels::calculateActivationRangeQuantized(luci_actfunc(options->fused_activation_function()),
80                                              output, &activation_min, &activation_max);
81
82   // Compute padding
83   const int32_t input_height = Tensor::dim(input, 1);
84   const int32_t input_width = Tensor::dim(input, 2);
85
86   const int32_t output_height = kernels::computeOutputSize(
87     luci_padding(options->padding()), input_height, options->filter_height(), options->stride_h());
88   const int32_t output_width = kernels::computeOutputSize(
89     luci_padding(options->padding()), input_width, options->filter_width(), options->stride_w());
90
91   const auto padding_height = kernels::computePadding(options->stride_h(), 1, input_height,
92                                                       options->filter_height(), output_height);
93   const auto padding_width = kernels::computePadding(options->stride_w(), 1, input_width,
94                                                      options->filter_width(), output_width);
95
96   tflite::PoolParams params{};
97   params.padding_values.height = padding_height;
98   params.padding_values.width = padding_width;
99   params.stride_height = options->stride_h();
100   params.stride_width = options->stride_w();
101   params.filter_height = options->filter_height();
102   params.filter_width = options->filter_width();
103   params.quantized_activation_min = activation_min;
104   params.quantized_activation_max = activation_max;
105
106   const auto *input_data = runtime_graph->getDataByTensor(input);
107   auto *output_data = runtime_graph->getDataByTensor(output);
108
109   tflite::reference_ops::MaxPool(
110     params, kernels::getTensorShape(input), kernels::getTensorData<uint8_t>(input_data),
111     kernels::getTensorShape(output), kernels::getTensorData<uint8_t>(output_data));
112 }
113
114 void evalSInt16(const circle::Tensor *input, const circle::Tensor *output,
115                 const circle::Pool2DOptions *options, BaseRuntimeGraph *runtime_graph)
116 {
117   int32_t activation_min{};
118   int32_t activation_max{};
119   kernels::calculateActivationRangeQuantized(luci_actfunc(options->fused_activation_function()),
120                                              output, &activation_min, &activation_max);
121
122   // Compute padding
123   const int32_t input_height = Tensor::dim(input, 1);
124   const int32_t input_width = Tensor::dim(input, 2);
125
126   const int32_t output_height = kernels::computeOutputSize(
127     luci_padding(options->padding()), input_height, options->filter_height(), options->stride_h());
128   const int32_t output_width = kernels::computeOutputSize(
129     luci_padding(options->padding()), input_width, options->filter_width(), options->stride_w());
130
131   const auto padding_height = kernels::computePadding(options->stride_h(), 1, input_height,
132                                                       options->filter_height(), output_height);
133   const auto padding_width = kernels::computePadding(options->stride_w(), 1, input_width,
134                                                      options->filter_width(), output_width);
135
136   tflite::PoolParams params{};
137   params.padding_values.height = padding_height;
138   params.padding_values.width = padding_width;
139   params.stride_height = options->stride_h();
140   params.stride_width = options->stride_w();
141   params.filter_height = options->filter_height();
142   params.filter_width = options->filter_width();
143   params.quantized_activation_min = activation_min;
144   params.quantized_activation_max = activation_max;
145
146   const auto *input_data = runtime_graph->getDataByTensor(input);
147   auto *output_data = runtime_graph->getDataByTensor(output);
148
149   tflite::reference_integer_ops::MaxPool(
150     params, kernels::getTensorShape(input), kernels::getTensorData<int16_t>(input_data),
151     kernels::getTensorShape(output), kernels::getTensorData<int16_t>(output_data));
152 }
153
154 #endif // DIS_QUANT
155
156 } // namespace
157
158 void configure_kernel_CircleMaxPool2D(const circle::Operator *cur_op,
159                                       BaseRuntimeGraph *runtime_graph)
160 {
161   const auto input_index = cur_op->inputs()->operator[](0);
162   const auto output_index = cur_op->outputs()->operator[](0);
163
164   assert(input_index != -1);
165   assert(output_index != -1);
166
167   const auto input = runtime_graph->getCircleTensorByIndex(input_index);
168   const auto output = runtime_graph->getCircleTensorByIndex(output_index);
169
170   LUCI_INTERPRETER_CHECK(Tensor::element_type(input) == Tensor::element_type(output));
171   assert(Tensor::num_dims(input) == 4);
172
173 #ifndef DIS_QUANT
174   if (Tensor::element_type(input) == DataType::U8)
175   {
176     LUCI_INTERPRETER_CHECK(std::abs(Tensor::scale(output) - Tensor::scale(input)) <= 1.0e-6);
177     LUCI_INTERPRETER_CHECK(Tensor::zero_point(output) == Tensor::zero_point(input));
178   }
179   else if (Tensor::element_type(input) == DataType::S16)
180   {
181     LUCI_INTERPRETER_CHECK(std::abs(Tensor::scale(output) - Tensor::scale(input)) <= 1.0e-6);
182     LUCI_INTERPRETER_CHECK(Tensor::zero_point(input) == 0 && Tensor::zero_point(output) == 0);
183   }
184 #endif // DIS_QUANT
185 }
186
187 void execute_kernel_CircleMaxPool2D(const circle::Operator *cur_op, BaseRuntimeGraph *runtime_graph,
188                                     bool)
189 {
190   const auto input_index = cur_op->inputs()->operator[](0);
191   const auto output_index = cur_op->outputs()->operator[](0);
192
193   assert(input_index != -1);
194   assert(output_index != -1);
195
196   const auto input = runtime_graph->getCircleTensorByIndex(input_index);
197   auto output = runtime_graph->getCircleTensorByIndex(output_index);
198
199   const auto *options = cur_op->builtin_options_as_Pool2DOptions();
200
201   switch (Tensor::element_type(input))
202   {
203 #ifndef DIS_FLOAT
204     case DataType::FLOAT32:
205       evalFloat(input, output, options, runtime_graph);
206       break;
207 #endif // DIS_FLOAT
208 #ifndef DIS_QUANT
209     case DataType::U8:
210       evalQuantized(input, output, options, runtime_graph);
211       break;
212     case DataType::S16:
213       evalSInt16(input, output, options, runtime_graph);
214       break;
215 #endif // DIS_QUANT
216     default:
217       assert(false && "Unsupported type.");
218   }
219 }
220
221 } // namespace luci_interpreter