2 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
3 * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #ifndef __NNFW_CKER_REDUCEMEAN_H__
19 #define __NNFW_CKER_REDUCEMEAN_H__
21 #include "cker/Shape.h"
22 #include "cker/operation/Reduce.h"
29 float round_nearest(float value)
33 return static_cast<float>(static_cast<int>(value - 0.5f));
37 return static_cast<float>(static_cast<int>(value + 0.5f));
40 template <typename Out, typename In>
41 Out mean_reducer(const Out data1, const In data2, int normalizer)
43 return data1 + static_cast<Out>(data2) / normalizer;
46 template <typename In> int sum_reducer(const int data1, const In data2)
48 return data1 + static_cast<int>(data2);
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),
57 const auto input_dims = input_shape.DimsData();
58 const auto input_num_dims = input_shape.DimensionsCount();
60 // Reset input iterator.
61 for (int idx = 0; idx < input_num_dims; ++idx)
65 // Compute number of output elements
66 for (int idx = 0; idx < num_axis; ++idx)
68 normalizer *= input_dims[axis[idx]];
70 // Iterate through input_data.
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));
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)
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)
95 // Compute number of output elements
96 for (int idx = 0; idx < num_axis; ++idx)
98 normalizer *= input_dims[axis[idx]];
100 // Iterate through input_data.
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));
111 class ReduceMean : public Reduce
114 ReduceMean() : Reduce(){};
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)
120 // Reset output data.
121 if (!InitTensorDataForReduce(output_shape, init_value, output_data))
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();
130 for (size_t idx = 0; idx < num_axes; idx++)
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];
137 prepare(num_dims, resolved_axis_size);
140 int num_resolved_axis = 0;
141 if (!ResolveAxis(input_shape.DimensionsCount(), axes, resolved_axis_data(), &num_resolved_axis))
146 return num_resolved_axis;
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))
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)
162 return ReduceMeanImpl<In, Out>(input_data, input_shape, resolved_axis_data(), num_resolved_axis,
163 temp_index_data(), reducer, output_data);
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))
172 size_t num_outputs = 1;
173 auto output_dims = output_shape.DimsData();
175 for (size_t idx = 0; idx < static_cast<size_t>(output_shape.DimensionsCount()); idx++)
177 num_outputs *= output_dims[idx];
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)
188 ReduceSumQuantImpl<In>(input_data, input_shape, resolved_axis_data(), num_resolved_axis,
189 temp_index_data(), reducer, _temp_sum.data());
192 float scale = input_scale / output_scale;
193 float bias = -input_offset * scale;
194 for (size_t idx = 0; idx < num_outputs; idx++)
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);
207 std::vector<int> _temp_sum;
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)
214 UNUSED_RELEASE(output_shape);
215 assert(input_shape.DimensionsCount() > 0);
217 m_obj.ReduceOp<In, Out>(input_shape, input_data, output_shape, output_data, axes, true, (Out)0,
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)
226 UNUSED_RELEASE(output_shape);
227 assert(input_shape.DimensionsCount() > 0);
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,
234 template <typename In, typename Out>
235 void MeanAxis1And2(const Shape &input_shape, const In *input_data, const Shape &output_shape,
238 UNUSED_RELEASE(output_shape);
239 assert(input_shape.DimensionsCount() == 4);
240 assert(output_shape.DimensionsCount() == 4);
242 const int output_batch = output_shape.Dims(0);
243 const int output_depth = output_shape.Dims(3);
245 const int input_height = input_shape.Dims(1);
246 const int input_width = input_shape.Dims(2);
248 for (int out_b = 0; out_b < output_batch; ++out_b)
250 for (int out_d = 0; out_d < output_depth; ++out_d)
253 for (int in_h = 0; in_h < input_height; ++in_h)
255 for (int in_w = 0; in_w < input_width; ++in_w)
257 value += input_data[Offset(input_shape, out_b, in_h, in_w, out_d)];
260 output_data[Offset(output_shape, out_b, 0, 0, out_d)] = value / (input_width * input_height);
268 #endif // __NNFW_CKER_REDUCEMEAN_H__