ONE - On-device Neural Engine
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
PALReduceCommon.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved
3 * Copyright 2020 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 ONERT_MICRO_PAL_REDUCE_COMMON_H
19#define ONERT_MICRO_PAL_REDUCE_COMMON_H
20
21#include "PALUtils.h"
22
23namespace onert_micro
24{
25namespace execute
26{
27namespace pal
28{
29
30// This method parses the input 'axis' to remove duplicates and handle negative
31// values, and returns a valid 'out_axis'
32inline bool resolveAxis(const int num_dims, const int *axis, const int64_t num_axis, int *out_axis,
33 int *out_num_axis)
34{
35 *out_num_axis = 0; // Just in case.
36 // Short-circuit axis resolution for scalars; the axis will go unused.
37 if (num_dims == 0)
38 {
39 return true;
40 }
41 // o(n^2) is fine since out_num_axis should be really small, mostly <= 4
42 for (int64_t idx = 0; idx < num_axis; ++idx)
43 {
44 // Handle negative index. A positive index 'p_idx' can be represented as a
45 // negative index 'n_idx' as: n_idx = p_idx-num_dims
46 // eg: For num_dims=3, [0, 1, 2] is the same as [-3, -2, -1] */
47 int current = axis[idx] < 0 ? (axis[idx] + num_dims) : axis[idx];
48 if (current < 0 || current >= num_dims)
49 {
50 return false;
51 }
52 bool is_dup = false;
53 for (int j = 0; j < *out_num_axis; ++j)
54 {
55 if (out_axis[j] == current)
56 {
57 is_dup = true;
58 break;
59 }
60 }
61 if (!is_dup)
62 {
63 if (*out_num_axis > 1)
64 {
65 return false;
66 }
67 out_axis[*out_num_axis] = current;
68 *out_num_axis += 1;
69 }
70 }
71 return true;
72}
73
74// Computes the generic value (i.e., sum/max/min/prod) of elements across
75// dimensions given in axis. It needs to pass in init_value and reducer.
76template <typename T>
77inline bool ReduceGeneric(const T *input_data, const int *input_dims, const int input_num_dims,
78 T *output_data, const int *axis, const int64_t num_axis_dimensions,
79 T init_value, const int output_flat_size, T reducer(const T, const T))
80{
81 // Return early when input shape has zero dim.
82 for (int i = 0; i < input_num_dims; ++i)
83 {
84 if (input_dims[i] == 0)
85 return false;
86 }
87
88 for (size_t idx = 0; idx < output_flat_size; ++idx)
89 {
90 output_data[idx] = init_value;
91 }
92
93 // Resolve axis.
94 int num_resolved_axis = 0;
95 int resolved_axis[2];
96
97 if (!resolveAxis(input_num_dims, axis, num_axis_dimensions, resolved_axis, &num_resolved_axis))
98 {
99 return false;
100 }
101
102 int temp_index[5];
103 // Reset input iterator.
104 for (int idx = 0; idx < input_num_dims; ++idx)
105 {
106 temp_index[idx] = 0;
107 }
108 // Iterate through input_data.
109 do
110 {
111 size_t input_offset = reducedOutputOffset(input_num_dims, input_dims, temp_index, 0, nullptr);
112 size_t output_offset =
113 reducedOutputOffset(input_num_dims, input_dims, temp_index, num_resolved_axis, axis);
114 output_data[output_offset] = reducer(output_data[output_offset], input_data[input_offset]);
115 } while (nextIndex(input_num_dims, input_dims, temp_index));
116
117 return true;
118}
119
120// This method expects that output_data has been initialized.
121template <typename T>
122inline bool reduceSumImpl(const T *input_data, const int *input_dims, const int input_num_dims,
123 T *output_data, const int *axis, const int num_axis,
124 const int num_outputs)
125{
126 return ReduceGeneric<T>(input_data, input_dims, input_num_dims, output_data, axis, num_axis,
127 static_cast<T>(0), num_outputs,
128 [](const T current, const T in) -> T { return in + current; });
129}
130
131template <typename T>
132inline bool Mean(const int *input_dims, const T *input_data, const int input_num_dims,
133 T *output_data, const int num_outputs, const int *axis,
134 const int num_axis_dimensions)
135{
136 if (!reduceSumImpl<T>(input_data, input_dims, input_num_dims, output_data, axis,
137 num_axis_dimensions, num_outputs))
138 {
139 return false;
140 }
141
142 // Resolve axis again for computing mean
143 int num_resolved_axis = 0;
144 int resolved_axis[2];
145
146 if (!resolveAxis(input_num_dims, axis, num_axis_dimensions, resolved_axis, &num_resolved_axis))
147 {
148 return false;
149 }
150
151 // Calculate mean by dividing output_data by num of aggregated element.
152 size_t num_elements_in_axis = 1;
153 for (int idx = 0; idx < num_resolved_axis; ++idx)
154 {
155 size_t current = static_cast<size_t>(input_dims[resolved_axis[idx]]);
156 // Overflow prevention.
157 if (current > (std::numeric_limits<size_t>::max() / num_elements_in_axis))
158 {
159 return false;
160 }
161 num_elements_in_axis *= current;
162 }
163
164 if (num_elements_in_axis > 0)
165 {
166 for (size_t idx = 0; idx < num_outputs; ++idx)
167 {
168 output_data[idx] = static_cast<T>(output_data[idx] / static_cast<T>(num_elements_in_axis));
169 }
170 }
171 return true;
172}
173
174} // namespace pal
175} // namespace execute
176} // namespace onert_micro
177
178#endif // ONERT_MICRO_PAL_REDUCE_COMMON_H
bool resolveAxis(const int num_dims, const int *axis, const int64_t num_axis, int *out_axis, int *out_num_axis)
bool nextIndex(const int32_t num_dims, const int32_t *dims, int32_t *current)
Definition PALUtils.h:175
bool Mean(const int *input_dims, const T *input_data, const int input_num_dims, T *output_data, const int num_outputs, const int *axis, const int num_axis_dimensions)
bool ReduceGeneric(const T *input_data, const int *input_dims, const int input_num_dims, T *output_data, const int *axis, const int64_t num_axis_dimensions, T init_value, const int output_flat_size, T reducer(const T, const T))
size_t reducedOutputOffset(const int32_t num_dims, const int32_t *dims, const int32_t *index, const int32_t num_axis, const int32_t *axis)
Definition PALUtils.h:143
bool reduceSumImpl(const T *input_data, const int *input_dims, const int input_num_dims, T *output_data, const int *axis, const int num_axis, const int num_outputs)