From c6fa1d0429153a35d8fa3cbbcab28c999696f4fa Mon Sep 17 00:00:00 2001 From: =?utf8?q?Shubham=20Gupta/System=20SW=20/SRI-Bangalore/Engineer/?= =?utf8?q?=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 5 Nov 2018 06:41:09 +0530 Subject: [PATCH] Implementation of Generic Permute CL Kernel (#3114) This patch will add generic permute kernel supporting all permutations for nD Tensors This kernel is required for Reshape and Transpose op Signed-off-by: shubham --- .../core/CL/kernels/CLPermuteExKernel.h | 73 +++++++++++ .../arm_compute/runtime/CL/functions/CLPermuteEx.h | 52 ++++++++ libs/ARMComputeEx/src/core/CL/CLKernelLibrary.cpp | 5 + .../src/core/CL/cl_kernels/permute_ex.cl | 72 +++++++++++ .../src/core/CL/kernels/CLPermuteExKernel.cpp | 133 +++++++++++++++++++++ .../src/runtime/CL/functions/CLPermuteEx.cpp | 39 ++++++ 6 files changed, 374 insertions(+) create mode 100644 libs/ARMComputeEx/arm_compute/core/CL/kernels/CLPermuteExKernel.h create mode 100644 libs/ARMComputeEx/arm_compute/runtime/CL/functions/CLPermuteEx.h create mode 100644 libs/ARMComputeEx/src/core/CL/cl_kernels/permute_ex.cl create mode 100644 libs/ARMComputeEx/src/core/CL/kernels/CLPermuteExKernel.cpp create mode 100644 libs/ARMComputeEx/src/runtime/CL/functions/CLPermuteEx.cpp diff --git a/libs/ARMComputeEx/arm_compute/core/CL/kernels/CLPermuteExKernel.h b/libs/ARMComputeEx/arm_compute/core/CL/kernels/CLPermuteExKernel.h new file mode 100644 index 0000000..e97713c --- /dev/null +++ b/libs/ARMComputeEx/arm_compute/core/CL/kernels/CLPermuteExKernel.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright (c) 2016-2018 ARM Limited. + * + * 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. + */ +#ifndef __ARM_COMPUTE_CLPERMUTEEXKERNEL_H__ +#define __ARM_COMPUTE_CLPERMUTEEXKERNEL_H__ + +#include "arm_compute/core/CL/ICLKernel.h" + +namespace arm_compute +{ +class ICLTensor; + +/** OpenCL kernel to perform tensor permutation. + * + * Permutes given a permutation vector + */ +class CLPermuteExKernel : public ICLKernel +{ +public: + /** Default constructor */ + CLPermuteExKernel(); + /** Prevent instances of this class from being copied (As this class contains pointers) */ + CLPermuteExKernel(const CLPermuteExKernel &) = delete; + /** Prevent instances of this class from being copied (As this class contains pointers) */ + CLPermuteExKernel &operator=(const CLPermuteExKernel &) = delete; + /** Allow instances of this class to be moved */ + CLPermuteExKernel(CLPermuteExKernel &&) = default; + /** Allow instances of this class to be moved */ + CLPermuteExKernel &operator=(CLPermuteExKernel &&) = default; + /** Set the input and output of the kernel. + * + * @param[in] input The input tensor to permute. Data types supported: + * U8/S8/QS8/QASYMM8/U16/S16/QS16/F16/U32/S32/F32 + * @param[in] output The output tensor. Data types supported: Same as @p input + * @param[in] perm Permutation vector + */ + void configure(const ICLTensor *input, ICLTensor *output, const PermutationVector &perm); + /** Static function to check if given info will lead to a valid configuration of @ref + * CLPermuteKernel + * + * @param[in] input First tensor input info. Data types supported: + * U8/S8/QS8/QASYMM8/U16/S16/QS16/F16/U32/S32/F32. + * @param[in] output Output tensor info. Data types supported: same as @p input. + * @param[in] perm Permutation vector + * + * @return a status + */ + static Status validate(const ITensorInfo *input, const ITensorInfo *output, + const PermutationVector &perm); + + // Inherited methods overridden: + void run(const Window &window, cl::CommandQueue &queue) override; + +private: + const ICLTensor *_input; + ICLTensor *_output; + PermutationVector _perm; +}; +} // arm_compute +#endif /*__ARM_COMPUTE_CLPERMUTEEXKERNEL_H__ */ diff --git a/libs/ARMComputeEx/arm_compute/runtime/CL/functions/CLPermuteEx.h b/libs/ARMComputeEx/arm_compute/runtime/CL/functions/CLPermuteEx.h new file mode 100644 index 0000000..20368fe --- /dev/null +++ b/libs/ARMComputeEx/arm_compute/runtime/CL/functions/CLPermuteEx.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright (c) 2016-2018 ARM Limited. + * + * 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. + */ +#ifndef __ARM_COMPUTE_CLPERMUTEEX_H__ +#define __ARM_COMPUTE_CLPERMUTEEX_H__ + +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/CL/ICLSimpleFunction.h" + +namespace arm_compute +{ +class ICLTensor; + +/** Basic function to execute an @ref CLPermuteKernel. */ +class CLPermuteEx : public ICLSimpleFunction +{ +public: + /** Set the input and output tensors. + * + * @param[in] input The input tensor to permute. Data types supported: + * U8/S8/QS8/QASYMM8/U16/S16/QS16/F16/U32/S32/F32 + * @param[in] output The output tensor. Data types supported: Same as @p input + * @param[in] perm Permutation vector + */ + void configure(const ICLTensor *input, ICLTensor *output, const PermutationVector &perm); + /** Static function to check if given info will lead to a valid configuration of @ref CLPermute. + * + * @param[in] input First tensor input info. Data types supported: + * U8/S8/QS8/QASYMM8/U16/S16/QS16/F16/U32/S32/F32. + * @param[in] output Output tensor info. Data types supported: same as @p input. + * @param[in] perm Permutation vector + * + * @return a status + */ + static Status validate(const ITensorInfo *input, const ITensorInfo *output, + const PermutationVector &perm); +}; +} +#endif /*__ARM_COMPUTE_CLPERMUTEEX_H__ */ diff --git a/libs/ARMComputeEx/src/core/CL/CLKernelLibrary.cpp b/libs/ARMComputeEx/src/core/CL/CLKernelLibrary.cpp index 9f2a3fc..7aed9cc 100644 --- a/libs/ARMComputeEx/src/core/CL/CLKernelLibrary.cpp +++ b/libs/ARMComputeEx/src/core/CL/CLKernelLibrary.cpp @@ -222,6 +222,7 @@ const std::map CLKernelLibraryEx::_kernel_program_map {"permute_201", "permute.cl"}, {"permute_120", "permute.cl"}, {"permute_3201", "permute.cl"}, + {"permute_generic", "permute_ex.cl"}, {"pixelwise_mul_float", "pixelwise_mul_float.cl"}, {"pixelwise_mul_int", "pixelwise_mul_int.cl"}, {"pixelwise_mul_qasymm8", "pixelwise_mul_quantized.cl"}, @@ -407,6 +408,10 @@ const std::map CLKernelLibraryEx::_program_source_map "topkv2_quicksort.cl", #include "./cl_kernels/topkv2_quicksort.clembed" }, + { + "permute_ex.cl", +#include "./cl_kernels/permute_ex.clembed" + }, #endif /* EMBEDDED_KERNELS */ }; diff --git a/libs/ARMComputeEx/src/core/CL/cl_kernels/permute_ex.cl b/libs/ARMComputeEx/src/core/CL/cl_kernels/permute_ex.cl new file mode 100644 index 0000000..f0c5d6c --- /dev/null +++ b/libs/ARMComputeEx/src/core/CL/cl_kernels/permute_ex.cl @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright (c) 2017 ARM Limited. + * + * 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 "helpers.h" + +#if defined(DATA_TYPE) && defined(DEPTH_IN) && defined(P1) && defined(P2) && defined(P3) && defined(P4) +/** Perform a Generic permute operation on an input tensor of Shape DCHW. + * + * @attention Data type can be passed using the -DDATA_TYPE compile flag, e.g. -DDATA_TYPE=float + * @attention Input tensor depth should be given as a preprocessor argument using -DDEPTH_IN=size. e.g. -DDEPTH_IN=16 + * @attention Permutation vector is passed as a preprocessor arguement using -DP1, -DP2, -DP3 and -DP4=int, e.g. -DP1=2 + * + * @param[in] input_ptr Pointer to the source image. Supported data types: U8/S8/QS8/QASYMM8/U1 +6/S16/QS16/F16/U32/S32/F32 + * @param[in] input_stride_x Stride of the source image in X dimension (in bytes) + * @param[in] input_step_x input_stride_x * number of elements along X processed per workitem(in b +ytes) + * @param[in] input_stride_y Stride of the source image in Y dimension (in bytes) + * @param[in] input_step_y input_stride_y * number of elements along Y processed per workitem(in b +ytes) + * @param[in] input_stride_z Stride of the source tensor in Z dimension (in bytes) + * @param[in] input_step_z input_stride_z * number of elements along Z processed per workitem(in b +ytes) + * @param[in] input_offset_first_element_in_bytes The offset of the first element in the source image + * @param[out] output_ptr Pointer to the destination image. Supported data types: same as @p inpu +t_ptr + * @param[in] output_stride_x Stride of the destination image in X dimension (in bytes) + * @param[in] output_step_x output_stride_x * number of elements along X processed per workitem(in bytes) + * @param[in] output_stride_y Stride of the destination image in Y dimension (in bytes) + * @param[in] output_step_y output_stride_y * number of elements along Y processed per workitem(in +bytes) + * @param[in] output_stride_z Stride of the source tensor in Z dimension (in bytes) + * @param[in] output_step_z output_stride_z * number of elements along Z processed per workitem(in bytes) + * @param[in] output_stride_w Stride of the source tensor in W dimension (in bytes) + * @param[in] output_step_w output_stride_w * number of elements along W processed per workitem(in bytes) + * @param[in] output_offset_first_element_in_bytes The offset of the first element in the destination image + */ +__kernel void permute_generic( + TENSOR4D_DECLARATION(input), + TENSOR4D_DECLARATION(output)) +{ + Tensor4D in = CONVERT_TO_TENSOR4D_STRUCT(input, DEPTH_IN); + Tensor4D out = CONVERT_TO_TENSOR4D_STRUCT_NO_STEP(output, 0); + + int out_index[4]; + int in_index[4]; + in_index[0] = get_global_id(0);//W + in_index[1] = get_global_id(1);//H + in_index[2] = get_global_id(2) % DEPTH_IN;//C + in_index[3] = get_global_id(2) / DEPTH_IN;//B + out_index[0] = in_index[P1]; + out_index[1] = in_index[P2]; + out_index[2] = in_index[P3]; + out_index[3] = in_index[P4]; + + *((__global DATA_TYPE *)tensor4D_offset(&out, out_index[0],out_index[1],out_index[2],out_index[3])) = *((__global DATA_TYPE *)in.ptr); +} +#endif // defined(DATA_TYPE) && defined(DEPTH_IN) && defined(P1) && defined(P2) && defined(P3) && defined(P4) diff --git a/libs/ARMComputeEx/src/core/CL/kernels/CLPermuteExKernel.cpp b/libs/ARMComputeEx/src/core/CL/kernels/CLPermuteExKernel.cpp new file mode 100644 index 0000000..c6d1ad1 --- /dev/null +++ b/libs/ARMComputeEx/src/core/CL/kernels/CLPermuteExKernel.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright (c) 2016-2018 ARM Limited. + * + * 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 "arm_compute/core/CL/kernels/CLPermuteExKernel.h" + +#include "arm_compute/core/CL/CLHelpers.h" +#include "arm_compute/core/CL/CLKernelLibrary.h" +#include "arm_compute/core/CL/CLKernelLibraryEx.h" +#include "arm_compute/core/CL/ICLTensor.h" +#include "arm_compute/core/CL/OpenCL.h" +#include "arm_compute/core/Error.h" +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/core/utils/misc/ShapeCalculator.h" +#include "support/ToolchainSupport.h" + +using namespace arm_compute; + +namespace +{ +TensorShape get_output_shape(const ITensorInfo *input, const PermutationVector &perm) +{ + TensorShape output_shape = input->tensor_shape(); + permute(output_shape, perm); + return output_shape; +} + +Status validate_arguments(const ITensorInfo *input, const ITensorInfo *output, + const PermutationVector &perm) +{ + ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN( + input, 1, DataType::U8, DataType::S8, DataType::QS8, DataType::QASYMM8, DataType::U16, + DataType::S16, DataType::QS16, DataType::U32, DataType::S32, DataType::F16, DataType::F32); + + const TensorShape output_shape = + misc::shape_calculator::compute_permutation_output_shape(*input, perm); + + // Validate configured output + if (output->total_size() != 0) + { + ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DIMENSIONS(output->tensor_shape(), output_shape); + ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input, output); + ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_FIXED_POINT(input, output); + } + return Status{}; +} +} // namespace + +CLPermuteExKernel::CLPermuteExKernel() : _input(nullptr), _output(nullptr), _perm() {} + +void CLPermuteExKernel::configure(const ICLTensor *input, ICLTensor *output, + const PermutationVector &perm) +{ + ARM_COMPUTE_ERROR_ON_NULLPTR(input, output); + ARM_COMPUTE_ERROR_THROW_ON(validate_arguments(input->info(), output->info(), perm)); + + _input = input; + _output = output; + _perm = perm; + + const TensorShape output_shape = get_output_shape(input->info(), perm); + // Output auto inizialitation if not yet initialized + auto_init_if_empty(*output->info(), input->info()->clone()->set_tensor_shape(output_shape)); + + // Create kernel + std::set build_opts; + + build_opts.emplace("-DDATA_TYPE=" + get_cl_type_from_data_type(input->info()->data_type())); + build_opts.emplace("-DDEPTH_IN=" + support::cpp11::to_string(input->info()->dimension(2))); + + // New positions of batch(D), height(H), width(w) and channel(C) based on permutation vector + build_opts.emplace("-DP1=" + support::cpp11::to_string(perm[0])); + build_opts.emplace("-DP2=" + support::cpp11::to_string(perm[1])); + build_opts.emplace("-DP3=" + support::cpp11::to_string(perm[2])); + build_opts.emplace("-DP4=" + support::cpp11::to_string(perm[3])); + _kernel = static_cast( + CLKernelLibraryEx::get().create_kernel("permute_generic", build_opts)); + + // Configure kernel window + Window win = calculate_max_window(*input->info(), Steps()); + + // The CLPermute doesn't need padding so update_window_and_padding() can be skipped + Coordinates coord; + coord.set_num_dimensions(output->info()->num_dimensions()); + output->info()->set_valid_region(ValidRegion(coord, output->info()->tensor_shape())); + + ICLKernel::configure(win); +} + +Status CLPermuteExKernel::validate(const ITensorInfo *input, const ITensorInfo *output, + const PermutationVector &perm) +{ + ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output); + ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments(input, output, perm)); + + return Status{}; +} + +void CLPermuteExKernel::run(const Window &window, cl::CommandQueue &queue) +{ + ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(this); + ARM_COMPUTE_ERROR_ON_MISMATCHING_WINDOWS(ICLKernel::window(), window); + + Window slice_in = window.first_slice_window_4D().collapse(ICLKernel::window(), 2, 4); + + // Setup output slice + Window slice_out(slice_in); + slice_out.set(Window::DimX, Window::Dimension(0, 0, 0)); + slice_out.set(Window::DimY, Window::Dimension(0, 0, 0)); + slice_out.set(Window::DimZ, Window::Dimension(0, 0, 0)); + slice_out.set(3, Window::Dimension(0, 0, 0)); + + do + { + unsigned int idx = 0; + add_4D_tensor_argument(idx, _input, slice_in); + add_4D_tensor_argument(idx, _output, slice_out); + enqueue(queue, *this, slice_in); + } while (window.slide_window_slice_4D(slice_in) && window.slide_window_slice_4D(slice_out)); +} diff --git a/libs/ARMComputeEx/src/runtime/CL/functions/CLPermuteEx.cpp b/libs/ARMComputeEx/src/runtime/CL/functions/CLPermuteEx.cpp new file mode 100644 index 0000000..099e56c --- /dev/null +++ b/libs/ARMComputeEx/src/runtime/CL/functions/CLPermuteEx.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright (c) 2016-2018 ARM Limited. + * + * 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 "arm_compute/runtime/CL/functions/CLPermuteEx.h" + +#include "arm_compute/core/CL/ICLTensor.h" +#include "arm_compute/core/CL/kernels/CLPermuteExKernel.h" +#include "arm_compute/core/Error.h" +#include "support/ToolchainSupport.h" + +using namespace arm_compute; + +void CLPermuteEx::configure(const ICLTensor *input, ICLTensor *output, + const PermutationVector &perm) +{ + auto k = arm_compute::support::cpp14::make_unique(); + k->configure(input, output, perm); + _kernel = std::move(k); +} + +Status CLPermuteEx::validate(const ITensorInfo *input, const ITensorInfo *output, + const PermutationVector &perm) +{ + ARM_COMPUTE_RETURN_ON_ERROR(CLPermuteExKernel::validate(input, output, perm)); + return Status{}; +} -- 2.7.4