6dd81aba5b8287afa2d0a2561473c469c2ad924e
[platform/core/ml/nnfw.git] / onert-micro / luci-interpreter / src / kernels / AveragePool2D.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 "kernels/AveragePool2D.h"
19
20 #include "kernels/Utils.h"
21
22 #include "PALAveragePool2d.h"
23
24 namespace luci_interpreter
25 {
26
27 namespace kernels
28 {
29
30 AveragePool2D::AveragePool2D(const Tensor *input, Tensor *output, Tensor *scratchpad,
31                              const Pool2DParams &params)
32   : KernelWithParams<Pool2DParams>({input}, {output, scratchpad}, params)
33 {
34 }
35
36 void AveragePool2D::configure()
37 {
38   if (input()->element_type() != output()->element_type())
39   {
40     assert(false && "Input Tensor and Output Tensor Type must be same");
41   }
42   if (input()->shape().num_dims() != 4)
43   {
44     assert(false && "Input Tensor Shape must be 4-D");
45   }
46   const Shape &input_shape = input()->shape();
47
48   const int32_t batches = input_shape.dim(0);
49   const int32_t input_height = input_shape.dim(1);
50   const int32_t input_width = input_shape.dim(2);
51   const int32_t depth = input_shape.dim(3);
52
53   const int32_t output_height =
54     computeOutputSize(_params.padding, input_height, _params.filter_height, _params.stride_height);
55   const int32_t output_width =
56     computeOutputSize(_params.padding, input_width, _params.filter_width, _params.stride_width);
57
58   _padding_height =
59     computePadding(_params.stride_height, 1, input_height, _params.filter_height, output_height);
60   _padding_width =
61     computePadding(_params.stride_width, 1, input_width, _params.filter_width, output_width);
62   if (input()->element_type() == DataType::U8)
63   {
64     LUCI_INTERPRETER_CHECK(std::abs(output()->scale() - input()->scale()) <= 1.0e-6);
65     LUCI_INTERPRETER_CHECK(output()->zero_point() == input()->zero_point());
66   }
67   else if (input()->element_type() == DataType::S16)
68   {
69     LUCI_INTERPRETER_CHECK(std::abs(output()->scale() - input()->scale()) <= 1.0e-6);
70     LUCI_INTERPRETER_CHECK(input()->zero_point() == 0 && output()->zero_point() == 0);
71   }
72   else if (input()->element_type() == DataType::S8)
73   {
74     LUCI_INTERPRETER_CHECK(std::abs(output()->scale() - input()->scale()) <= 1.0e-6);
75     LUCI_INTERPRETER_CHECK(output()->zero_point() == input()->zero_point());
76   }
77   // TODO: enable it only if kernel with dynamic shapes
78   output()->resize({batches, output_height, output_width, depth});
79
80   auto scratchpad = getOutputTensors()[1];
81   luci_interpreter_pal::SetupScratchpadTensor(scratchpad, input()->element_type(),
82                                               getTensorShape(input()), getTensorShape(output()));
83 }
84
85 void AveragePool2D::execute() const
86 {
87   switch (input()->element_type())
88   {
89     case DataType::FLOAT32:
90       evalFloat();
91       break;
92     case DataType::U8:
93       evalQuantized();
94       break;
95     case DataType::S16:
96       evalSInt16();
97       break;
98     case DataType::S8:
99       evalSInt8();
100       break;
101     default:
102       assert(false && "Unsupported type.");
103   }
104 }
105
106 void AveragePool2D::evalFloat() const
107 {
108   float activation_min{};
109   float activation_max{};
110   calculateActivationRange(_params.activation, &activation_min, &activation_max);
111
112   tflite::PoolParams params{};
113   params.padding_values.height = _padding_height;
114   params.padding_values.width = _padding_width;
115   params.stride_height = _params.stride_height;
116   params.stride_width = _params.stride_width;
117   params.filter_height = _params.filter_height;
118   params.filter_width = _params.filter_width;
119   params.float_activation_min = activation_min;
120   params.float_activation_max = activation_max;
121
122   tflite::reference_ops::AveragePool(params, getTensorShape(input()), getTensorData<float>(input()),
123                                      getTensorShape(output()), getTensorData<float>(output()));
124 }
125
126 void AveragePool2D::evalQuantized() const
127 {
128   int32_t activation_min{};
129   int32_t activation_max{};
130   calculateActivationRangeQuantized(_params.activation, output(), &activation_min, &activation_max);
131
132   tflite::PoolParams params{};
133   params.padding_values.height = _padding_height;
134   params.padding_values.width = _padding_width;
135   params.stride_height = _params.stride_height;
136   params.stride_width = _params.stride_width;
137   params.filter_height = _params.filter_height;
138   params.filter_width = _params.filter_width;
139   params.quantized_activation_min = activation_min;
140   params.quantized_activation_max = activation_max;
141
142   tflite::reference_ops::AveragePool(params, getTensorShape(input()),
143                                      getTensorData<uint8_t>(input()), getTensorShape(output()),
144                                      getTensorData<uint8_t>(output()));
145 }
146
147 void AveragePool2D::evalSInt8() const
148 {
149   int32_t activation_min{};
150   int32_t activation_max{};
151   calculateActivationRangeQuantized(_params.activation, output(), &activation_min, &activation_max);
152   tflite::PoolParams params{};
153   params.padding_values.height = _padding_height;
154   params.padding_values.width = _padding_width;
155   params.stride_height = _params.stride_height;
156   params.stride_width = _params.stride_width;
157   params.filter_height = _params.filter_height;
158   params.filter_width = _params.filter_width;
159   params.quantized_activation_min = activation_min;
160   params.quantized_activation_max = activation_max;
161
162   auto scratchpad = getOutputTensors()[1];
163   int8_t *scratchpad_data = nullptr;
164   if (scratchpad->is_allocatable())
165     scratchpad_data = scratchpad->data<int8_t>();
166
167   luci_interpreter_pal::AveragePool<int8_t>(
168     params, getTensorShape(input()), getTensorData<int8_t>(input()), getTensorShape(output()),
169     getTensorData<int8_t>(output()), getTensorShape(scratchpad), scratchpad_data);
170 }
171
172 void AveragePool2D::evalSInt16() const
173 {
174   int32_t activation_min{};
175   int32_t activation_max{};
176   calculateActivationRangeQuantized(_params.activation, output(), &activation_min, &activation_max);
177
178   tflite::PoolParams params{};
179   params.padding_values.height = _padding_height;
180   params.padding_values.width = _padding_width;
181   params.stride_height = _params.stride_height;
182   params.stride_width = _params.stride_width;
183   params.filter_height = _params.filter_height;
184   params.filter_width = _params.filter_width;
185   params.quantized_activation_min = activation_min;
186   params.quantized_activation_max = activation_max;
187
188   tflite::reference_integer_ops::AveragePool(
189     params, getTensorShape(input()), getTensorData<int16_t>(input()), //
190     getTensorShape(output()), getTensorData<int16_t>(output()));
191 }
192
193 } // namespace kernels
194 } // namespace luci_interpreter