Imported Upstream version 1.12.0
[platform/core/ml/nnfw.git] / compute / cker / include / cker / operation / ReduceMean.h
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 __NNFW_CKER_REDUCEMEAN_H__
19 #define __NNFW_CKER_REDUCEMEAN_H__
20
21 #include "cker/Shape.h"
22 #include "cker/operation/Reduce.h"
23
24 namespace nnfw
25 {
26 namespace cker
27 {
28
29 float round_nearest(float value)
30 {
31   if (value < 0)
32   {
33     return static_cast<float>(static_cast<int>(value - 0.5f));
34   }
35   else
36   {
37     return static_cast<float>(static_cast<int>(value + 0.5f));
38   }
39 }
40 template <typename Out, typename In>
41 Out mean_reducer(const Out data1, const In data2, int normalizer)
42 {
43   return data1 + static_cast<Out>(data2) / normalizer;
44 }
45
46 template <typename In> int sum_reducer(const int data1, const In data2)
47 {
48   return data1 + static_cast<int>(data2);
49 }
50
51 template <typename In, typename Out>
52 inline bool ReduceMeanImpl(const In *input_data, const Shape &input_shape, const int *axis,
53                            const int num_axis, int *input_iter,
54                            Out reducer(const Out current, const In in, int normalizer),
55                            Out *output_data)
56 {
57   const auto input_dims = input_shape.DimsData();
58   const auto input_num_dims = input_shape.DimensionsCount();
59   int normalizer = 1;
60   // Reset input iterator.
61   for (int idx = 0; idx < input_num_dims; ++idx)
62   {
63     input_iter[idx] = 0;
64   }
65   // Compute number of output elements
66   for (int idx = 0; idx < num_axis; ++idx)
67   {
68     normalizer *= input_dims[axis[idx]];
69   }
70   // Iterate through input_data.
71   do
72   {
73     size_t input_offset = ReducedOutputOffset(input_num_dims, input_dims, input_iter, 0, nullptr);
74     size_t output_offset =
75       ReducedOutputOffset(input_num_dims, input_dims, input_iter, num_axis, axis);
76     output_data[output_offset] =
77       reducer(output_data[output_offset], input_data[input_offset], normalizer);
78   } while (NextIndex(input_num_dims, input_dims, input_iter));
79   return true;
80 }
81
82 template <typename In>
83 inline size_t ReduceSumQuantImpl(const In *input_data, const Shape &input_shape, const int *axis,
84                                  const int num_axis, int *input_iter,
85                                  int reducer(const int current, const In in), int *temp_sum)
86 {
87   const auto input_dims = input_shape.DimsData();
88   const auto input_num_dims = input_shape.DimensionsCount();
89   size_t normalizer = 1;
90   // Reset input iterator.
91   for (int idx = 0; idx < input_num_dims; ++idx)
92   {
93     input_iter[idx] = 0;
94   }
95   // Compute number of output elements
96   for (int idx = 0; idx < num_axis; ++idx)
97   {
98     normalizer *= input_dims[axis[idx]];
99   }
100   // Iterate through input_data.
101   do
102   {
103     size_t input_offset = ReducedOutputOffset(input_num_dims, input_dims, input_iter, 0, nullptr);
104     size_t output_offset =
105       ReducedOutputOffset(input_num_dims, input_dims, input_iter, num_axis, axis);
106     temp_sum[output_offset] = reducer(temp_sum[output_offset], input_data[input_offset]);
107   } while (NextIndex(input_num_dims, input_dims, input_iter));
108   return normalizer;
109 }
110
111 class ReduceMean : public Reduce
112 {
113 public:
114   ReduceMean() : Reduce(){};
115
116   template <typename T>
117   int PrepareforReduce(const Shape &input_shape, const Shape &output_shape,
118                        const std::vector<int> &axes, T *output_data, T init_value)
119   {
120     // Reset output data.
121     if (!InitTensorDataForReduce(output_shape, init_value, output_data))
122     {
123       return -1;
124     }
125     const auto input_dims = input_shape.DimsData();
126     const int num_dims = input_shape.DimensionsCount();
127     int resolved_axis_size = 1;
128     const auto num_axes = axes.size();
129
130     for (size_t idx = 0; idx < num_axes; idx++)
131     {
132       int current = axes[idx] < 0 ? (axes[idx] + num_dims) : axes[idx];
133       assert(current >= 0 && current < num_dims);
134       resolved_axis_size *= input_dims[current];
135     }
136
137     prepare(num_dims, resolved_axis_size);
138
139     // Resolve axis.
140     int num_resolved_axis = 0;
141     if (!ResolveAxis(input_shape.DimensionsCount(), axes, resolved_axis_data(), &num_resolved_axis))
142     {
143       return -1;
144     }
145
146     return num_resolved_axis;
147   }
148
149   // Computes the generic value (i.e., sum/max/min/prod) of elements across
150   // dimensions given in axis. It needs to pass in init_value and reducer.
151   template <typename In, typename Out>
152   inline bool ReduceOp(const Shape &input_shape, const In *input_data, const Shape &output_shape,
153                        Out *output_data, const std::vector<int> &axes, bool, Out init_value,
154                        Out reducer(const Out current, const Out in, int normalizer))
155   {
156     int num_resolved_axis;
157     num_resolved_axis = PrepareforReduce(input_shape, output_shape, axes, output_data, init_value);
158     if (num_resolved_axis == -1)
159     {
160       return false;
161     }
162     return ReduceMeanImpl<In, Out>(input_data, input_shape, resolved_axis_data(), num_resolved_axis,
163                                    temp_index_data(), reducer, output_data);
164   }
165
166   template <typename In, typename Out>
167   inline bool ReduceOp(const Shape &input_shape, const In *input_data, float input_scale,
168                        int32_t input_offset, const Shape &output_shape, Out *output_data,
169                        float output_scale, int32_t output_offset, const std::vector<int> &axes,
170                        bool, Out init_value, int reducer(const int current, const In in))
171   {
172     size_t num_outputs = 1;
173     auto output_dims = output_shape.DimsData();
174
175     for (size_t idx = 0; idx < static_cast<size_t>(output_shape.DimensionsCount()); idx++)
176     {
177       num_outputs *= output_dims[idx];
178     }
179     _temp_sum.resize(num_outputs, 0);
180     int num_resolved_axis;
181     num_resolved_axis = PrepareforReduce(input_shape, output_shape, axes, output_data, init_value);
182     if (num_resolved_axis == -1)
183     {
184       return false;
185     }
186
187     size_t normalizer =
188       ReduceSumQuantImpl<In>(input_data, input_shape, resolved_axis_data(), num_resolved_axis,
189                              temp_index_data(), reducer, _temp_sum.data());
190     if (num_outputs > 0)
191     {
192       float scale = input_scale / output_scale;
193       float bias = -input_offset * scale;
194       for (size_t idx = 0; idx < num_outputs; idx++)
195       {
196         float float_mean = static_cast<float>(_temp_sum[idx]) / normalizer;
197         float result = std::min(round_nearest(float_mean * scale + bias + output_offset),
198                                 static_cast<float>(std::numeric_limits<Out>::max()));
199         result = std::max(result, static_cast<float>(std::numeric_limits<Out>::min()));
200         output_data[idx] = static_cast<Out>(result);
201       }
202     }
203     return false;
204   }
205
206 private:
207   std::vector<int> _temp_sum;
208 };
209
210 template <typename In, typename Out>
211 void Mean(const Shape &input_shape, const In *input_data, const Shape &output_shape,
212           Out *output_data, const std::vector<int> &axes)
213 {
214   UNUSED_RELEASE(output_shape);
215   assert(input_shape.DimensionsCount() > 0);
216   ReduceMean m_obj;
217   m_obj.ReduceOp<In, Out>(input_shape, input_data, output_shape, output_data, axes, true, (Out)0,
218                           mean_reducer);
219 }
220
221 template <typename In, typename Out>
222 void MeanQ8Asymm(const Shape &input_shape, const In *input_data, float input_scale,
223                  int32_t input_offset, const Shape &output_shape, Out *output_data,
224                  float output_scale, int32_t output_offset, const std::vector<int> &axes)
225 {
226   UNUSED_RELEASE(output_shape);
227   assert(input_shape.DimensionsCount() > 0);
228   ReduceMean m_obj;
229   m_obj.ReduceOp<In, Out>(input_shape, input_data, input_scale, input_offset, output_shape,
230                           output_data, output_scale, output_offset, axes, true, (Out)0,
231                           sum_reducer);
232 }
233
234 template <typename In, typename Out>
235 void MeanAxis1And2(const Shape &input_shape, const In *input_data, const Shape &output_shape,
236                    Out *output_data)
237 {
238   UNUSED_RELEASE(output_shape);
239   assert(input_shape.DimensionsCount() == 4);
240   assert(output_shape.DimensionsCount() == 4);
241
242   const int output_batch = output_shape.Dims(0);
243   const int output_depth = output_shape.Dims(3);
244
245   const int input_height = input_shape.Dims(1);
246   const int input_width = input_shape.Dims(2);
247
248   for (int out_b = 0; out_b < output_batch; ++out_b)
249   {
250     for (int out_d = 0; out_d < output_depth; ++out_d)
251     {
252       float value = 0;
253       for (int in_h = 0; in_h < input_height; ++in_h)
254       {
255         for (int in_w = 0; in_w < input_width; ++in_w)
256         {
257           value += input_data[Offset(input_shape, out_b, in_h, in_w, out_d)];
258         }
259       }
260       output_data[Offset(output_shape, out_b, 0, 0, out_d)] = value / (input_width * input_height);
261     }
262   }
263 }
264
265 } // namespace cker
266 } // namespace nnfw
267
268 #endif // __NNFW_CKER_REDUCEMEAN_H__