2 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "ReduceLayer.h"
19 #include "OperationUtils.h"
21 #include "cker/neon/neon_check.h"
22 #include <cker/operation/Reduce.h>
37 void evalLogic(const IPortableTensor *input, IPortableTensor *output, const std::vector<int> &axes,
38 bool keep_dims, T init_value, nnfw::cker::Reduce &reduce_kernel,
39 T reducer(const T current, const T in))
41 reduce_kernel.prepare(input->getShape().rank(), axes.size());
43 reduce_kernel.ReduceGeneric<T>(getShape(input), getBuffer<T>(input), getShape(output),
44 getBuffer<T>(output), axes, keep_dims, init_value, reducer);
48 throw std::runtime_error{"Reduce: Fail to run"};
53 std::function<void(const IPortableTensor *, IPortableTensor *, const std::vector<int> &)>
54 evalType(bool keep_dims, nnfw::cker::Reduce &reduce_kernel, ReduceType reduce_type)
58 case ReduceType::kSum:
59 return std::bind(&evalLogic<T>, std::placeholders::_1, std::placeholders::_2,
60 std::placeholders::_3, keep_dims, static_cast<T>(0), reduce_kernel,
61 [](const T current, const T in) -> T { return in + current; });
63 case ReduceType::kProd:
64 return std::bind(&evalLogic<T>, std::placeholders::_1, std::placeholders::_2,
65 std::placeholders::_3, keep_dims, static_cast<T>(1), reduce_kernel,
66 [](const T current, const T in) -> T { return in * current; });
68 case ReduceType::kMax:
70 &evalLogic<T>, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
71 keep_dims, std::numeric_limits<T>::lowest(), reduce_kernel,
72 [](const T current, const T in) -> T { return (in > current) ? in : current; });
74 case ReduceType::kMin:
76 &evalLogic<T>, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
77 keep_dims, std::numeric_limits<T>::max(), reduce_kernel,
78 [](const T current, const T in) -> T { return (in < current) ? in : current; });
81 throw std::runtime_error{"Reduce: Unsupported reduce type"};
85 // Template specialization for bool type
87 std::function<void(const IPortableTensor *, IPortableTensor *, const std::vector<int> &)>
88 evalType<bool>(bool keep_dims, nnfw::cker::Reduce &reduce_kernel, ReduceType reduce_type)
92 case ReduceType::kAny:
93 return std::bind(&evalLogic<bool>, std::placeholders::_1, std::placeholders::_2,
94 std::placeholders::_3, keep_dims, false, reduce_kernel,
95 [](const bool current, const bool in) -> bool { return in || current; });
97 case ReduceType::kAll:
98 return std::bind(&evalLogic<bool>, std::placeholders::_1, std::placeholders::_2,
99 std::placeholders::_3, keep_dims, true, reduce_kernel,
100 [](const bool current, const bool in) -> bool { return in && current; });
103 throw std::runtime_error{"Reduce: Unsupported reduce type"};
107 std::function<void(const IPortableTensor *, IPortableTensor *, const std::vector<int> &)>
108 generateKernelGeneric(const IPortableTensor *input, bool keep_dims,
109 nnfw::cker::Reduce &reduce_kernel, ReduceType reduce_type)
111 switch (input->data_type())
113 case OperandType::FLOAT32:
114 return evalType<float>(keep_dims, reduce_kernel, reduce_type);
115 case OperandType::INT32:
116 return evalType<int32_t>(keep_dims, reduce_kernel, reduce_type);
117 case OperandType::BOOL8:
118 return evalType<bool>(keep_dims, reduce_kernel, reduce_type);
120 throw std::runtime_error{"Reduce(generic): unsupported data type"};
124 // TODO Refine this function
125 void evalSumQuantized(const IPortableTensor *input, IPortableTensor *output,
126 const std::vector<int> &axes, bool keep_dims,
127 nnfw::cker::Reduce &reduce_kernel)
129 const bool same_scale = (input->data_scale() == output->data_scale() &&
130 input->data_zero_point() == output->data_zero_point());
132 reduce_kernel.prepare(input->getShape().rank(), axes.size());
136 std::vector<int32_t> temp_sum(output->getShape().num_elements());
137 bool result = reduce_kernel.QuantizedMeanOrSum<uint8_t, int32_t>(
138 getBuffer<uint8_t>(input), input->data_zero_point(), input->data_scale(), getShape(input),
139 getBuffer<uint8_t>(output), output->data_zero_point(), output->data_scale(), getShape(output),
140 axes, keep_dims, temp_sum.data(), true,
141 [](const int32_t current, const uint8_t in) -> int32_t {
142 const int32_t actual_in = static_cast<int32_t>(in);
143 return current + actual_in;
148 throw std::runtime_error{"Reduce: Fail to run"};
154 const auto kernel = generateKernelGeneric(input, keep_dims, reduce_kernel, ReduceType::kSum);
155 kernel(input, output, axes);
160 ReduceLayer::ReduceLayer()
161 : _input(nullptr), _axes(nullptr), _output(nullptr), _reduce_kernel(new nnfw::cker::Reduce()),
162 _kernel(), _reduceType(ReduceType::kInvalid)
167 ReduceLayer::~ReduceLayer() = default;
169 void ReduceLayer::configure(const IPortableTensor *input, const IPortableTensor *axes,
170 IPortableTensor *output, ReduceType reduceType, bool keep_dims)
175 _reduceType = reduceType;
179 case ReduceType::kSum:
180 if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
182 _kernel = std::bind(&evalSumQuantized, std::placeholders::_1, std::placeholders::_2,
183 std::placeholders::_3, keep_dims, *_reduce_kernel);
186 _kernel = generateKernelGeneric(_input, keep_dims, *_reduce_kernel, ReduceType::kSum);
188 case ReduceType::kProd:
189 _kernel = generateKernelGeneric(_input, keep_dims, *_reduce_kernel, ReduceType::kProd);
191 case ReduceType::kMax:
192 _kernel = generateKernelGeneric(_input, keep_dims, *_reduce_kernel, ReduceType::kMax);
194 case ReduceType::kMin:
195 _kernel = generateKernelGeneric(_input, keep_dims, *_reduce_kernel, ReduceType::kMin);
197 case ReduceType::kAny:
198 _kernel = generateKernelGeneric(_input, keep_dims, *_reduce_kernel, ReduceType::kAny);
200 case ReduceType::kAll:
201 _kernel = generateKernelGeneric(_input, keep_dims, *_reduce_kernel, ReduceType::kAll);
204 throw std::runtime_error{"Reduce: Unsupported reduce type"};
208 void ReduceLayer::run()
210 const auto axes = getReducerAxes(_axes);
212 int32_t rank = _input->getShape().rank();
213 if (_input->data_type() == ir::DataType::FLOAT32 && _reduceType == ReduceType::kSum &&
214 axes.size() == 1 && (axes[0] == -1 || axes[0] == rank - 1))
216 OptimizedReduceSum(getBuffer<float>(_input), getShape(_input), getBuffer<float>(_output));
220 _kernel(_input, _output, axes);
225 } // namespace backend