ONE - On-device Neural Engine
Loading...
Searching...
No Matches
ReduceMean.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 __NNFW_CKER_REDUCEMEAN_H__
19#define __NNFW_CKER_REDUCEMEAN_H__
20
21#include "cker/Shape.h"
23
24namespace nnfw
25{
26namespace cker
27{
28
29float 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}
40template <typename Out, typename In>
41Out mean_reducer(const Out data1, const In data2, int normalizer)
42{
43 return data1 + static_cast<Out>(data2) / normalizer;
44}
45
46template <typename In> int sum_reducer(const int data1, const In data2)
47{
48 return data1 + static_cast<int>(data2);
49}
50
51template <typename In, typename Out>
52inline 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
82template <typename In>
83inline 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
111class ReduceMean : public Reduce
112{
113public:
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
206private:
207 std::vector<int> _temp_sum;
208};
209
210template <typename In, typename Out>
211void Mean(const Shape &input_shape, const In *input_data, const Shape &output_shape,
212 Out *output_data, const std::vector<int> &axes)
213{
214 assert(input_shape.DimensionsCount() > 0);
215 ReduceMean m_obj;
216 m_obj.ReduceOp<In, Out>(input_shape, input_data, output_shape, output_data, axes, true, (Out)0,
218}
219
220template <typename In, typename Out>
221void MeanQ8Asymm(const Shape &input_shape, const In *input_data, float input_scale,
222 int32_t input_offset, const Shape &output_shape, Out *output_data,
223 float output_scale, int32_t output_offset, const std::vector<int> &axes)
224{
225 assert(input_shape.DimensionsCount() > 0);
226 ReduceMean m_obj;
227 m_obj.ReduceOp<In, Out>(input_shape, input_data, input_scale, input_offset, output_shape,
228 output_data, output_scale, output_offset, axes, true, (Out)0,
230}
231
232template <typename In, typename Out>
233void MeanAxis1And2(const Shape &input_shape, const In *input_data, const Shape &output_shape,
234 Out *output_data)
235{
236 assert(input_shape.DimensionsCount() == 4);
237 assert(output_shape.DimensionsCount() == 4);
238
239 const int output_batch = output_shape.Dims(0);
240 const int output_depth = output_shape.Dims(3);
241
242 const int input_height = input_shape.Dims(1);
243 const int input_width = input_shape.Dims(2);
244
245 for (int out_b = 0; out_b < output_batch; ++out_b)
246 {
247 for (int out_d = 0; out_d < output_depth; ++out_d)
248 {
249 float value = 0;
250 for (int in_h = 0; in_h < input_height; ++in_h)
251 {
252 for (int in_w = 0; in_w < input_width; ++in_w)
253 {
254 value += input_data[Offset(input_shape, out_b, in_h, in_w, out_d)];
255 }
256 }
257 output_data[Offset(output_shape, out_b, 0, 0, out_d)] = value / (input_width * input_height);
258 }
259 }
260}
261
262} // namespace cker
263} // namespace nnfw
264
265#endif // __NNFW_CKER_REDUCEMEAN_H__
int32_t * resolved_axis_data(void)
Definition Reduce.h:358
void prepare(size_t temp_index_size, size_t resolved_axis_size)
Definition Reduce.h:235
int32_t * temp_index_data(void)
Definition Reduce.h:362
int PrepareforReduce(const Shape &input_shape, const Shape &output_shape, const std::vector< int > &axes, T *output_data, T init_value)
Definition ReduceMean.h:117
bool ReduceOp(const Shape &input_shape, const In *input_data, float input_scale, int32_t input_offset, const Shape &output_shape, Out *output_data, float output_scale, int32_t output_offset, const std::vector< int > &axes, bool, Out init_value, int reducer(const int current, const In in))
Definition ReduceMean.h:167
bool ReduceOp(const Shape &input_shape, const In *input_data, const Shape &output_shape, Out *output_data, const std::vector< int > &axes, bool, Out init_value, Out reducer(const Out current, const Out in, int normalizer))
Definition ReduceMean.h:152
int32_t DimensionsCount() const
Definition Shape.h:91
int32_t Dims(int i) const
Definition Shape.h:92
int32_t * DimsData()
Definition Shape.h:112
const luci_interpreter::RuntimeShape output_shape
int sum_reducer(const int data1, const In data2)
Definition ReduceMean.h:46
int Offset(const Shape &shape, int i0, int i1, int i2, int i3)
Definition Shape.h:237
void MeanQ8Asymm(const Shape &input_shape, const In *input_data, float input_scale, int32_t input_offset, const Shape &output_shape, Out *output_data, float output_scale, int32_t output_offset, const std::vector< int > &axes)
Definition ReduceMean.h:221
bool NextIndex(const int num_dims, const int *dims, int *current)
Definition Utils.h:387
size_t ReducedOutputOffset(const int num_dims, const int *dims, const int *index, const int num_axis, const int *axis)
Definition Utils.h:420
Out mean_reducer(const Out data1, const In data2, int normalizer)
Definition ReduceMean.h:41
size_t ReduceSumQuantImpl(const In *input_data, const Shape &input_shape, const int *axis, const int num_axis, int *input_iter, int reducer(const int current, const In in), int *temp_sum)
Definition ReduceMean.h:83
bool ReduceMeanImpl(const In *input_data, const Shape &input_shape, const int *axis, const int num_axis, int *input_iter, Out reducer(const Out current, const In in, int normalizer), Out *output_data)
Definition ReduceMean.h:52
bool ResolveAxis(const int num_dims, const std::vector< int > &axes, int *out_axis, int *out_num_axis)
Definition Reduce.h:169
bool InitTensorDataForReduce(const Shape &shape, const T init_value, T *data)
Definition Reduce.h:208
float round_nearest(float value)
Definition ReduceMean.h:29
void MeanAxis1And2(const Shape &input_shape, const In *input_data, const Shape &output_shape, Out *output_data)
Definition ReduceMean.h:233
void Mean(const Shape &input_shape, const In *input_data, const Shape &output_shape, Out *output_data, const std::vector< int > &axes)
Definition ReduceMean.h:211
Definition topk_v2.h:30