blob: 777fc9e5e14c556ac65587d5d15288cfb3ad8c66 [file] [log] [blame]
Gian Marco Iodice76335eb2022-11-17 11:03:39 +00001/*
2 * Copyright (c) 2022 Arm Limited.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#include "src/gpu/cl/operators/ClIndirectConv2d.h"
25
26#include "arm_compute/core/KernelDescriptors.h"
27#include "arm_compute/core/Types.h"
28#include "arm_compute/core/utils/misc/ShapeCalculator.h"
29#include "arm_compute/runtime/CL/CLScheduler.h"
Gian Marco Iodice76335eb2022-11-17 11:03:39 +000030
31#include "src/common/utils/Log.h"
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010032#include "src/core/helpers/MemoryHelpers.h"
33#include "src/gpu/cl/kernels/ClIndirectConv2dAddressPrecalculationKernel.h"
34#include "src/gpu/cl/kernels/ClIndirectConv2dKernel.h"
35#include "src/gpu/cl/utils/ClAuxTensorHandler.h"
36#include "src/runtime/heuristics/indirect_conv/ClIndirectConvKernelConfig.h"
37#include "src/runtime/heuristics/indirect_conv/IClIndirectConvKernelConfig.h"
Gian Marco Iodice76335eb2022-11-17 11:03:39 +000038
Gian Marco Iodicea5cb79f2022-12-28 13:53:51 +000039using namespace arm_compute::cl_indirect_conv;
Gian Marco Iodice76335eb2022-11-17 11:03:39 +000040
41namespace arm_compute
42{
43namespace opencl
44{
45using namespace arm_compute::experimental;
46
47namespace
48{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010049DirectConvComputeKernelInfo
50config_indirect_convolution_nhwc(const ITensorInfo *src, const ITensorInfo *weights, const PadStrideInfo &conv_info)
Gian Marco Iodice76335eb2022-11-17 11:03:39 +000051{
52 // Get GPU target
53 GPUTarget gpu_target = CLScheduler::get().target();
54
Gian Marco Iodicea5cb79f2022-12-28 13:53:51 +000055 std::unique_ptr<IClIndirectConvKernelConfig> t = ClIndirectConvKernelConfigurationFactory::create(gpu_target);
Gian Marco Iodice76335eb2022-11-17 11:03:39 +000056
57 return t->configure(src, weights, conv_info);
58}
59
60} // namespace
61
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010062void ClIndirectConv2d::configure(const CLCompileContext &compile_context,
63 ITensorInfo *src,
64 ITensorInfo *weights,
65 ITensorInfo *biases,
66 ITensorInfo *dst,
67 const PadStrideInfo &conv_info,
68 const ActivationLayerInfo &act_info)
Gian Marco Iodice76335eb2022-11-17 11:03:39 +000069{
70 ARM_COMPUTE_ERROR_ON_NULLPTR(src);
71 ARM_COMPUTE_LOG_PARAMS(src, weights, biases, dst, conv_info, act_info);
72
73 // Reuse the direct convolution descriptor
Gian Marco Iodicea5cb79f2022-12-28 13:53:51 +000074 const DirectConvComputeKernelInfo desc = config_indirect_convolution_nhwc(src, weights, conv_info);
Gian Marco Iodice76335eb2022-11-17 11:03:39 +000075
76 // Configure indirect convolution kernels
77 auto k0 = std::make_unique<kernels::ClIndirectConv2dAddressPrecalculationKernel>();
78 auto k1 = std::make_unique<kernels::ClIndirectConv2dKernel>();
79
80 k0->set_target(CLScheduler::get().target());
81 k1->set_target(CLScheduler::get().target());
82
83 k0->configure(compile_context, src, weights, &_indirect_buffer, conv_info, desc);
84 k1->configure(compile_context, src, weights, biases, &_indirect_buffer, dst, conv_info, act_info, desc);
85
86 _addr_precalculation_kernel = std::move(k0);
87 _indirect_conv_kernel = std::move(k1);
88 _is_prepared = false;
89
90 // Tune kernels
91 CLScheduler::get().tune_kernel_static(*_indirect_conv_kernel);
92
93 // Request memory for the indirect buffer
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010094 _aux_mem[IndirectBuffer] =
95 MemoryInfo(offset_int_vec(IndirectBuffer), MemoryLifetime::Persistent, _indirect_buffer.total_size());
Gian Marco Iodice76335eb2022-11-17 11:03:39 +000096}
97
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010098Status ClIndirectConv2d::validate(const ITensorInfo *src,
99 const ITensorInfo *weights,
100 const ITensorInfo *biases,
101 const ITensorInfo *dst,
102 const PadStrideInfo &conv_info,
103 const ActivationLayerInfo &act_info)
Gian Marco Iodice76335eb2022-11-17 11:03:39 +0000104{
105 // Initialize the direct convolution descriptor
Gian Marco Iodicea5cb79f2022-12-28 13:53:51 +0000106 const DirectConvComputeKernelInfo desc = config_indirect_convolution_nhwc(src, weights, conv_info);
Gian Marco Iodice76335eb2022-11-17 11:03:39 +0000107
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100108 TensorShape ind_buffer_shape = misc::shape_calculator::compute_indirect_buffer_shape(
109 src->tensor_shape(), src->data_layout(), weights->tensor_shape(), conv_info, desc);
Gian Marco Iodice76335eb2022-11-17 11:03:39 +0000110
111 TensorInfo indirect_buffer(ind_buffer_shape, 1, DataType::S32);
112
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100113 ARM_COMPUTE_RETURN_ON_ERROR(kernels::ClIndirectConv2dAddressPrecalculationKernel::validate(
114 src, weights, &indirect_buffer, conv_info, desc));
115 ARM_COMPUTE_RETURN_ON_ERROR(kernels::ClIndirectConv2dKernel::validate(src, weights, biases, &indirect_buffer, dst,
116 conv_info, act_info, desc));
Gian Marco Iodice76335eb2022-11-17 11:03:39 +0000117
118 return Status{};
119}
120
121void ClIndirectConv2d::run(ITensorPack &tensors)
122{
123 CLAuxTensorHandler indirect_buffer(offset_int_vec(IndirectBuffer), _indirect_buffer, tensors, true);
124
125 prepare(tensors);
126
127 ITensorPack indirect_conv2d_pack(tensors);
128 indirect_conv2d_pack.add_const_tensor(ACL_SRC_3, indirect_buffer.get());
129
130 // Run indirect convolution
131 CLScheduler::get().enqueue_op(*_indirect_conv_kernel, indirect_conv2d_pack, true);
132}
133
134void ClIndirectConv2d::prepare(ITensorPack &constants)
135{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100136 if (!_is_prepared)
Gian Marco Iodice76335eb2022-11-17 11:03:39 +0000137 {
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100138 ICLTensor *indirect_buffer_aux =
139 utils::cast::polymorphic_downcast<ICLTensor *>(constants.get_tensor(offset_int_vec(IndirectBuffer)));
Gian Marco Iodice76335eb2022-11-17 11:03:39 +0000140 ARM_COMPUTE_ERROR_ON(indirect_buffer_aux == nullptr);
141
142 ARM_COMPUTE_LOG_INFO_WITH_FUNCNAME_ACL("Preparing indirect buffer");
143
144 CLAuxTensorHandler indirect_buffer(_indirect_buffer, *indirect_buffer_aux);
145 ARM_COMPUTE_ERROR_ON(indirect_buffer.get()->cl_buffer().get() == nullptr);
146
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100147 ITensorPack indirect_buffer_pack{{ACL_DST, indirect_buffer.get()}};
Gian Marco Iodice76335eb2022-11-17 11:03:39 +0000148 CLScheduler::get().enqueue_op(*_addr_precalculation_kernel, indirect_buffer_pack, true);
149
150 _is_prepared = true;
151 }
152}
153
154experimental::MemoryRequirements ClIndirectConv2d::workspace() const
155{
156 return _aux_mem;
157}
158} // namespace opencl
159} // namespace arm_compute