diff options
Diffstat (limited to 'runtimes/pure_arm_compute/src/internal/layers/SimpleArgMinMax.cc')
-rw-r--r-- | runtimes/pure_arm_compute/src/internal/layers/SimpleArgMinMax.cc | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/runtimes/pure_arm_compute/src/internal/layers/SimpleArgMinMax.cc b/runtimes/pure_arm_compute/src/internal/layers/SimpleArgMinMax.cc new file mode 100644 index 000000000..6d348e814 --- /dev/null +++ b/runtimes/pure_arm_compute/src/internal/layers/SimpleArgMinMax.cc @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "internal/layers/SimpleArgMinMax.h" +#include <arm_compute/runtime/CL/CLScheduler.h> + +void SimpleArgMinMax::configure(::arm_compute::ITensor *input, ::arm_compute::ITensor *output, + std::vector<uint32_t> axis, ::arm_compute::ArgOperation op) +{ + _input = input; + _output = output; + _axis = axis; + _input_rank = input->info()->num_dimensions(); + _op_type = op; +} + +inline const ::arm_compute::TensorShape +inferOutputShape(const ::arm_compute::TensorShape &input_shape, const std::vector<uint32_t> &axis, + int input_rank) +{ + ::arm_compute::TensorShape out_shape{}; + size_t dim = 1; + for (int i = 0; i < input_rank; ++i) + { + dim = input_shape[i]; + out_shape.set(i, dim); + } + + for (int i = 0; i < axis.size(); ++i) + { + out_shape.set(axis[i], 1); + } + + return out_shape; +} + +template <typename T> +inline T getArgMinMaxEle(const ::arm_compute::ITensor *input, + const ::arm_compute::TensorShape &input_shape, + const ::arm_compute::TensorShape &output_shape, const size_t b, + const size_t d, const size_t h, const size_t w, const int axis, + const ::arm_compute::ArgOperation op_type) +{ + // If output[dimention] == 1, will check all values of that dimension because of reducing + // dimension. + // Else will check only one value. + const size_t start_b = output_shape[3] == 1 ? 0 : b; + const size_t start_d = output_shape[2] == 1 ? 0 : d; + const size_t start_h = output_shape[1] == 1 ? 0 : h; + const size_t start_w = output_shape[0] == 1 ? 0 : w; + const size_t stop_b = output_shape[3] == 1 ? input_shape[3] - 1 : b; + const size_t stop_d = output_shape[2] == 1 ? input_shape[2] - 1 : d; + const size_t stop_h = output_shape[1] == 1 ? input_shape[1] - 1 : h; + const size_t stop_w = output_shape[0] == 1 ? input_shape[0] - 1 : w; + + ::arm_compute::Coordinates id{w, h, d, b}; + ::arm_compute::Coordinates min_max_id{w, h, d, b}; + + T value = *reinterpret_cast<T *>(input->ptr_to_element(id)); + T tval = *reinterpret_cast<T *>(input->ptr_to_element(id)); + + for (size_t in_b = start_b; in_b <= stop_b; ++in_b) + { + id.set(3, in_b); + for (size_t in_d = start_d; in_d <= stop_d; ++in_d) + { + id.set(2, in_d); + for (size_t in_h = start_h; in_h <= stop_h; ++in_h) + { + id.set(1, in_h); + for (size_t in_w = start_w; in_w <= stop_w; ++in_w) + { + id.set(0, in_w); + if (op_type == ::arm_compute::ArgOperation::MIN) + { + value = std::min<T>(value, *reinterpret_cast<T *>(input->ptr_to_element(id))); + } + else if (op_type == ::arm_compute::ArgOperation::MAX) + { + value = std::max<T>(value, *reinterpret_cast<T *>(input->ptr_to_element(id))); + } + else + throw std::runtime_error("This Arg operation is not supported, yet"); + + if (tval != value) + { + min_max_id = id; + tval = value; + } + } + } + } + } + + return min_max_id[axis]; +} + +template <typename T> +inline void +getArgMinMax(const ::arm_compute::ITensor *input, const ::arm_compute::TensorShape &input_shape, + const ::arm_compute::TensorShape &output_shape, ::arm_compute::ITensor *output, + const int axis, const ::arm_compute::ArgOperation op_type) +{ + ::arm_compute::Coordinates id; + for (size_t out_b = 0; out_b < output_shape[3]; ++out_b) + { + id.set(3, out_b); + for (size_t out_d = 0; out_d < output_shape[2]; ++out_d) + { + id.set(2, out_d); + for (size_t out_h = 0; out_h < output_shape[1]; ++out_h) + { + id.set(1, out_h); + for (size_t out_w = 0; out_w < output_shape[0]; ++out_w) + { + id.set(0, out_w); + *reinterpret_cast<int *>(output->ptr_to_element(id)) = getArgMinMaxEle<T>( + input, input_shape, output_shape, out_b, out_d, out_h, out_w, axis, op_type); + } + } + } + } +} + +void SimpleArgMinMax::run() +{ + if (::internal::arm_compute::isGpuMode()) + { + auto &q = ::arm_compute::CLScheduler::get().queue(); + + CAST_CL(_input)->map(q); + CAST_CL(_output)->map(q); + } + + ::arm_compute::TensorShape input_shape = _input->info()->tensor_shape(); + + // Axis dimension is 1 and size is 1. + // TODO support axis size > 1. + int axis_val = _axis[0]; + ::arm_compute::TensorShape output_shape = inferOutputShape(input_shape, _axis, _input_rank); + + _output->info()->set_tensor_shape(output_shape); + switch (_input->info()->data_type()) + { + case ::arm_compute::DataType::QASYMM8: + getArgMinMax<uint8_t>(_input, input_shape, output_shape, _output, axis_val, _op_type); + break; + case ::arm_compute::DataType::S32: + getArgMinMax<int32_t>(_input, input_shape, output_shape, _output, axis_val, _op_type); + break; + case ::arm_compute::DataType::F32: + getArgMinMax<float>(_input, input_shape, output_shape, _output, axis_val, _op_type); + break; + default: + ARM_COMPUTE_ERROR("DataType not supported"); + break; + } + + _output->info()->set_tensor_shape(output_shape); + + if (::internal::arm_compute::isGpuMode()) + { + auto &q = ::arm_compute::CLScheduler::get().queue(); + + CAST_CL(_input)->unmap(q); + CAST_CL(_output)->unmap(q); + } +} |