diff options
Diffstat (limited to 'runtimes/pure_arm_compute/src/internal/layers/SimpleSpaceToBatchND.cc')
-rw-r--r-- | runtimes/pure_arm_compute/src/internal/layers/SimpleSpaceToBatchND.cc | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/runtimes/pure_arm_compute/src/internal/layers/SimpleSpaceToBatchND.cc b/runtimes/pure_arm_compute/src/internal/layers/SimpleSpaceToBatchND.cc new file mode 100644 index 000000000..f53675b99 --- /dev/null +++ b/runtimes/pure_arm_compute/src/internal/layers/SimpleSpaceToBatchND.cc @@ -0,0 +1,142 @@ +/* + * 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/SimpleSpaceToBatchND.h" + +#include <arm_compute/runtime/CL/CLScheduler.h> + +void SimpleSpaceToBatchND::configure(::arm_compute::ITensor *input, + ::arm_compute::ITensor *block_size, + ::arm_compute::ITensor *padding_size, + ::arm_compute::ITensor *output) +{ + const auto rank = input->info()->num_dimensions(); + assert(rank == 4); + + _input = input; + _block_size = block_size; + _padding_size = padding_size; + _output = output; +} + +template <typename T> +inline void +SpaceToBatchND(const ::arm_compute::ITensor *input, const ::arm_compute::TensorShape &input_shape, + const ::arm_compute::ITensor *block_size, const ::arm_compute::ITensor *padding_size, + const ::arm_compute::ITensor *output, const ::arm_compute::TensorShape &output_shape, + T zero_value) +{ + const int input_batch = input_shape[3]; + const int input_height = input_shape[1]; + const int input_width = input_shape[0]; + + const int depth = output_shape[2]; + + const int padding_height_left = *reinterpret_cast<int *>(padding_size->ptr_to_element({0, 1})); + const int padding_height_right = *reinterpret_cast<int *>(padding_size->ptr_to_element({1, 1})); + const int padding_width_left = *reinterpret_cast<int *>(padding_size->ptr_to_element({0, 0})); + const int padding_width_right = *reinterpret_cast<int *>(padding_size->ptr_to_element({1, 0})); + const int padded_height = input_height + padding_height_left + padding_height_right; + const int padded_width = input_width + padding_width_left + padding_width_right; + + const int block_size_height = *reinterpret_cast<int *>(block_size->ptr_to_element({1})); + const int block_size_width = *reinterpret_cast<int *>(block_size->ptr_to_element({0})); + + assert(padding_height_left >= 0); + assert(padding_height_right >= 0); + assert(padding_width_left >= 0); + assert(padding_width_right >= 0); + assert(block_size_height >= 1); + assert(block_size_width >= 1); + assert(padded_height % block_size_height == 0); + assert(padded_width % block_size_width == 0); + assert(output->info()->dimension(3) == + input->info()->dimension(3) * (block_size_height * block_size_width)); + + for (int in_b = 0; in_b < input_batch; ++in_b) + { + for (int in_d = 0; in_d < depth; ++in_d) + { + for (int in_h = 0; in_h < padded_height; ++in_h) + { + for (int in_w = 0; in_w < padded_width; ++in_w) + { + const int out_d = in_d; + const int out_h = in_h / block_size_height; + const int out_w = in_w / block_size_width; + const int out_b = + in_b + + ((in_h % block_size_height) * block_size_width + in_w % block_size_width) * + input_batch; + + const ::arm_compute::Coordinates output_id{out_w, out_h, out_d, out_b}; + + if (in_h < padding_height_left || in_h >= (input_height + padding_height_left) || + in_w < padding_width_left || in_w >= (input_width + padding_width_left)) + { + *reinterpret_cast<T *>(output->ptr_to_element(output_id)) = zero_value; + } + else + { + const ::arm_compute::Coordinates input_id{in_w - padding_width_left, + in_h - padding_height_left, in_d, in_b}; + *reinterpret_cast<T *>(output->ptr_to_element(output_id)) = + *reinterpret_cast<T *>(input->ptr_to_element(input_id)); + } + } + } + } + } +} +void SimpleSpaceToBatchND::run() +{ + if (::internal::arm_compute::isGpuMode()) + { + auto &q = ::arm_compute::CLScheduler::get().queue(); + + CAST_CL(_input)->map(q); + CAST_CL(_block_size)->map(q); + CAST_CL(_padding_size)->map(q); + CAST_CL(_output)->map(q); + } + + switch (_input->info()->data_type()) + { + case ::arm_compute::DataType::U8: + case ::arm_compute::DataType::QASYMM8: + SpaceToBatchND<uint8_t>(_input, _input->info()->tensor_shape(), _block_size, _padding_size, + _output, _output->info()->tensor_shape(), + _input->info()->quantization_info().offset); + break; + case ::arm_compute::DataType::F32: + SpaceToBatchND<float>(_input, _input->info()->tensor_shape(), _block_size, _padding_size, + _output, _output->info()->tensor_shape(), 0.0f); + break; + default: + ARM_COMPUTE_ERROR("DataType not supported"); + break; + } + + if (::internal::arm_compute::isGpuMode()) + { + auto &q = ::arm_compute::CLScheduler::get().queue(); + + CAST_CL(_input)->unmap(q); + CAST_CL(_block_size)->unmap(q); + CAST_CL(_padding_size)->unmap(q); + CAST_CL(_output)->unmap(q); + } +} |