blob: e00f09563f31f9f5708d626fa33e9ad5f89bb3fc [file] [log] [blame]
SiCong Lif44bbc52022-08-29 18:25:51 +01001/*
Gunes Bayir3a1e1252023-01-03 21:26:09 +00002 * Copyright (c) 2022-2023 Arm Limited.
SiCong Lif44bbc52022-08-29 18:25:51 +01003 *
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 "arm_compute/dynamic_fusion/sketch/gpu/operators/GpuConv2d.h"
25
Ramy Elgammaldf6a3b02022-11-30 16:23:10 +000026#include "arm_compute/core/KernelDescriptors.h"
SiCong Lif44bbc52022-08-29 18:25:51 +010027#include "arm_compute/core/Validate.h"
SiCong Lif44bbc52022-08-29 18:25:51 +010028#include "arm_compute/core/utils/misc/ShapeCalculator.h"
Ramy Elgammaldf6a3b02022-11-30 16:23:10 +000029#include "arm_compute/runtime/CL/CLScheduler.h"
SiCong Lif44bbc52022-08-29 18:25:51 +010030
Ramy Elgammaldf6a3b02022-11-30 16:23:10 +000031#include "src/common/utils/Log.h"
SiCong Lif44bbc52022-08-29 18:25:51 +010032#include "src/core/helpers/AutoConfiguration.h"
33#include "src/dynamic_fusion/sketch/ArgumentPack.h"
34#include "src/dynamic_fusion/sketch/gpu/GpuWorkloadSketchImpl.h"
SiCong Lif44bbc52022-08-29 18:25:51 +010035#include "src/dynamic_fusion/sketch/gpu/components/cl/ClComponentDirectConv2d.h"
36#include "src/gpu/cl/kernels/gemm/ClGemmHelpers.h"
Ramy Elgammaldf6a3b02022-11-30 16:23:10 +000037#include "src/runtime/heuristics/direct_conv/ClDirectConvKernelConfig.h"
38#include "src/runtime/heuristics/direct_conv/IClDirectConvKernelConfig.h"
Ramy Elgammal404462a2022-11-08 02:14:46 +000039
SiCong Lif44bbc52022-08-29 18:25:51 +010040namespace arm_compute
41{
42namespace experimental
43{
44namespace dynamic_fusion
45{
46namespace
47{
Ramy Elgammaldf6a3b02022-11-30 16:23:10 +000048DirectConvComputeKernelInfo config_direct_convolution_nhwc(const ITensorInfo *src, const ITensorInfo *weights, const PadStrideInfo &conv_info)
49{
50 // Get GPU target
51 GPUTarget gpu_target = CLScheduler::get().target();
52
53 std::unique_ptr<arm_compute::cl_direct_conv::IClDirectConvKernelConfig> t = arm_compute::cl_direct_conv::ClDirectConvKernelConfigurationFactory::create(gpu_target);
54
55 return t->configure(src, weights, conv_info);
56}
57
SiCong Li81fdadd2022-11-23 09:58:18 +000058void calculate_and_init_dst_if_empty(ITensorInfo *dst, const ITensorInfo *src, const ITensorInfo *wei, const Conv2dAttributes &attributes)
59{
60 if(dst->total_size() == 0U)
61 {
62 const auto shape = misc::shape_calculator::compute_deep_convolution_shape(src->tensor_shape(), src->data_layout(), wei->tensor_shape(),
63 PadStrideInfo(attributes.stride().x(), attributes.stride().y(), attributes.pad().left,
64 attributes.pad().right,
65 attributes.pad().top, attributes.pad().bottom, DimensionRoundingType::FLOOR)); // use the default DimensionRoundingType
66
67 auto_init_if_empty(*dst, src->clone()->set_tensor_shape(shape));
68 }
69}
70
Gunes Bayir3a1e1252023-01-03 21:26:09 +000071/* A helper method to reduce the duplication in dst tensor initialization
72* when calling validate()
73*/
74Status is_supported_op_helper(const GpuWorkloadContext &context,
75 const ITensorInfo *src,
76 const ITensorInfo *wei,
77 const ITensorInfo *bia,
78 const ITensorInfo *dst,
79 const Conv2dAttributes &attributes)
SiCong Lif44bbc52022-08-29 18:25:51 +010080{
Gunes Bayir3a1e1252023-01-03 21:26:09 +000081 ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(src, wei);
SiCong Lif44bbc52022-08-29 18:25:51 +010082
Gunes Bayir3a1e1252023-01-03 21:26:09 +000083 TensorInfo dst_info_to_validate;
84 const ITensorInfo *dst_info_to_validate_ptr = &dst_info_to_validate;
85
Gunes Bayir3a1e1252023-01-03 21:26:09 +000086 if(dst != nullptr)
SiCong Lif44bbc52022-08-29 18:25:51 +010087 {
Gunes Bayir3a1e1252023-01-03 21:26:09 +000088 dst_info_to_validate_ptr = dst;
89 }
Gunes Bayircc287732023-01-19 15:56:00 +000090
91 calculate_and_init_dst_if_empty(&dst_info_to_validate, src, wei, attributes);
SiCong Lif44bbc52022-08-29 18:25:51 +010092
93 // Check support level
94 // Data type
95 ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(src, 1, DataType::F16, DataType::F32);
96 // Data layout
97 ARM_COMPUTE_RETURN_ERROR_ON_DATA_LAYOUT_NOT_IN(src, DataLayout::NHWC);
98
SiCong Li81fdadd2022-11-23 09:58:18 +000099 // Check components
Gunes Bayir3a1e1252023-01-03 21:26:09 +0000100 const auto gpu_target = context.gpu_target();
SiCong Li81fdadd2022-11-23 09:58:18 +0000101 if(context.gpu_language() == GpuLanguage::OpenCL)
SiCong Lif44bbc52022-08-29 18:25:51 +0100102 {
SiCong Li81fdadd2022-11-23 09:58:18 +0000103 const auto cl_compile_ctx = context.cl_compile_context();
SiCong Lif44bbc52022-08-29 18:25:51 +0100104 ARM_COMPUTE_RETURN_ERROR_ON(cl_compile_ctx == nullptr);
105 // Validate Direct Conv2d Component
106 {
107 const auto properties = IGpuKernelComponent::Properties().stage(UnitWorkloadStage{ UnitWorkloadStage::Stage::Run });
108 auto settings = ClComponentDirectConv2d::Settings();
109
SiCong Lif44bbc52022-08-29 18:25:51 +0100110 settings.fast_relaxed_math(
111 (gpu_target != GPUTarget::G71 && (gpu_target & GPUTarget::GPU_ARCH_MASK) == GPUTarget::BIFROST)
Gunes Bayir3a1e1252023-01-03 21:26:09 +0000112 && (dst_info_to_validate_ptr->data_type() == DataType::F32 || dst_info_to_validate_ptr->data_type() == DataType::F16));
SiCong Lif44bbc52022-08-29 18:25:51 +0100113
114 ArgumentPack<ITensorInfo> arguments;
115 arguments.add_const_tensor(ACL_SRC_0, src);
116 arguments.add_const_tensor(ACL_SRC_1, wei);
117 arguments.add_const_tensor(ACL_SRC_2, bia);
Gunes Bayir3a1e1252023-01-03 21:26:09 +0000118 arguments.add_const_tensor(ACL_DST_0, dst_info_to_validate_ptr);
SiCong Lif44bbc52022-08-29 18:25:51 +0100119 ARM_COMPUTE_RETURN_ON_ERROR(ClComponentDirectConv2d::validate(properties, arguments, attributes, settings));
120 }
121 }
122 else
123 {
124 ARM_COMPUTE_RETURN_ERROR_MSG("Unimplemented Gpu language");
125 }
126 return Status{};
127}
128
Gunes Bayir3a1e1252023-01-03 21:26:09 +0000129constexpr GpuOperatorType operator_type = GpuOperatorType::Complex;
130} // namespace
131
132Status GpuConv2d::is_supported_op(const GpuWorkloadContext &context,
133 const ITensorInfo *src,
134 const ITensorInfo *wei,
135 const ITensorInfo *bia,
136 const Conv2dAttributes &attributes)
137{
138 return is_supported_op_helper(context, src, wei, bia, nullptr, attributes);
139}
140
SiCong Li81fdadd2022-11-23 09:58:18 +0000141Status GpuConv2d::validate_op(const GpuWorkloadSketch &sketch,
142 const ITensorInfo *src,
143 const ITensorInfo *wei,
144 const ITensorInfo *bia,
SiCong Li81fdadd2022-11-23 09:58:18 +0000145 const Conv2dAttributes &attributes)
146{
Gunes Bayir3a1e1252023-01-03 21:26:09 +0000147 ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(src, wei);
SiCong Li81fdadd2022-11-23 09:58:18 +0000148
149 // Check if tensors have valid id. I.e. they are created from a sketch
Gunes Bayir3a1e1252023-01-03 21:26:09 +0000150 ARM_COMPUTE_RETURN_ERROR_ON(!src->has_valid_id() || !wei->has_valid_id());
SiCong Li81fdadd2022-11-23 09:58:18 +0000151 if(bia != nullptr)
152 {
153 ARM_COMPUTE_RETURN_ERROR_ON(!bia->has_valid_id());
154 }
155
Gunes Bayir3a1e1252023-01-03 21:26:09 +0000156 // This tensor info will have invalid id but because all the existing tensors in the
157 // sketch have valid ids and the DependencyGraph implementation has no notion of validness
158 // regarding tensor ids, it'll be just another tensor id and will validate
159 // Additionally, a new dst id is added every time in create_op, thus there's no need to validate it
160 TensorInfo dst_info_to_validate;
161
SiCong Li81fdadd2022-11-23 09:58:18 +0000162 // Auto initialize dst tensor info
SiCong Li81fdadd2022-11-23 09:58:18 +0000163 calculate_and_init_dst_if_empty(&dst_info_to_validate, src, wei, attributes);
164
165 // Perform fusion test
166 // Check if operator meets fusion constraints
167 ArgumentPack<ITensorInfo> tensors;
168 tensors.add_const_tensor(ACL_SRC_0, src);
169 tensors.add_const_tensor(ACL_SRC_1, wei);
170 tensors.add_const_tensor(ACL_SRC_2, bia);
171 tensors.add_const_tensor(ACL_DST_0, &dst_info_to_validate);
172 const auto op = sketch.implementation().operator_group().new_operator(operator_type, tensors);
173 ARM_COMPUTE_RETURN_ERROR_ON_MSG(!sketch.implementation().operator_group().try_add_operator(op),
174 "Operator fusion test failed. This operator cannot be fused into the workload");
175
176 // Check if configuration is supported
Gunes Bayir3a1e1252023-01-03 21:26:09 +0000177 return is_supported_op_helper(*sketch.gpu_context(), src, wei, bia, &dst_info_to_validate, attributes);
SiCong Li81fdadd2022-11-23 09:58:18 +0000178}
179
Gunes Bayir3a1e1252023-01-03 21:26:09 +0000180ITensorInfo *GpuConv2d::create_op(GpuWorkloadSketch &sketch,
181 ITensorInfo *src,
182 ITensorInfo *wei,
183 ITensorInfo *bia,
184 const Conv2dAttributes &attributes)
SiCong Lif44bbc52022-08-29 18:25:51 +0100185{
Gunes Bayir3a1e1252023-01-03 21:26:09 +0000186 ARM_COMPUTE_LOG_PARAMS(src, wei, bia, attributes);
Ramy Elgammaldf6a3b02022-11-30 16:23:10 +0000187 PadStrideInfo conv_info(attributes.stride().x(), attributes.stride().y(), attributes.pad().left,
188 attributes.pad().right,
189 attributes.pad().top, attributes.pad().bottom, DimensionRoundingType::FLOOR);
190 // Initialize the direct convolution descriptor
191 const DirectConvComputeKernelInfo desc = config_direct_convolution_nhwc(src, wei, conv_info);
192
SiCong Li5a2bc012023-01-12 12:54:49 +0000193 ITensorInfo *dst = sketch.implementation().create_virtual_tensor();
Gunes Bayir3a1e1252023-01-03 21:26:09 +0000194
SiCong Lif44bbc52022-08-29 18:25:51 +0100195 // Assert validation
Gunes Bayir3a1e1252023-01-03 21:26:09 +0000196 ARM_COMPUTE_ERROR_THROW_ON(GpuConv2d::validate_op(sketch, src, wei, bia, attributes));
SiCong Lif44bbc52022-08-29 18:25:51 +0100197 ARM_COMPUTE_ERROR_ON_NULLPTR(src, wei, dst);
SiCong Lif44bbc52022-08-29 18:25:51 +0100198
199 // Auto initialize dst tensor
SiCong Li81fdadd2022-11-23 09:58:18 +0000200 calculate_and_init_dst_if_empty(dst, src, wei, attributes);
SiCong Lif44bbc52022-08-29 18:25:51 +0100201
202 // Translate into components and add to component graph
203 auto &comp_graph = sketch.implementation().component_graph();
204
205 const auto sketch_ctx = sketch.implementation().context();
206
SiCong Li81fdadd2022-11-23 09:58:18 +0000207 const auto gpu_target = sketch_ctx->gpu_target();
SiCong Lif44bbc52022-08-29 18:25:51 +0100208
209 if(sketch_ctx->gpu_language() == GpuLanguage::OpenCL)
210 {
211 const auto cl_compile_ctx = sketch_ctx->cl_compile_context();
212 ARM_COMPUTE_ERROR_ON(cl_compile_ctx == nullptr);
213
214 // Add Direct Conv2d Component
215 {
216 auto properties = IGpuKernelComponent::Properties();
217 properties.stage(UnitWorkloadStage{ UnitWorkloadStage::Stage::Run });
218
219 auto settings = ClComponentDirectConv2d::Settings();
220
SiCong Lif44bbc52022-08-29 18:25:51 +0100221 settings.fast_relaxed_math(
222 (gpu_target != GPUTarget::G71 && (gpu_target & GPUTarget::GPU_ARCH_MASK) == GPUTarget::BIFROST)
223 && (dst->data_type() == DataType::F32 || dst->data_type() == DataType::F16));
224
Viet-Hoa Doe2e6d742023-03-01 15:46:10 +0000225 settings.direct_conv_descriptor(desc);
226
SiCong Lif44bbc52022-08-29 18:25:51 +0100227 if(settings.export_to_cl_image())
228 {
229 arm_compute::opencl::kernels::gemm::update_padding_for_cl_image(wei);
230 }
231
SiCong Lif44bbc52022-08-29 18:25:51 +0100232 ArgumentPack<ITensorInfo> arguments;
233 arguments.add_const_tensor(ACL_SRC_0, src);
234 arguments.add_const_tensor(ACL_SRC_1, wei);
235 arguments.add_const_tensor(ACL_SRC_2, bia);
236 arguments.add_const_tensor(ACL_DST_0, dst);
237 comp_graph.add_new_component<ClComponentDirectConv2d>(properties, arguments, attributes, settings);
238 }
239 }
240 else
241 {
242 ARM_COMPUTE_ERROR("Unimplemented Gpu language");
243 }
244
245 // Set up fusion test by adding to the Operator Group
246 // Note this has to be performed after all the components have been successfully added to the component graph
247
248 // Pack tensor infos
249 ArgumentPack<ITensorInfo> tensors;
250 tensors.add_const_tensor(ACL_SRC_0, src);
SiCong Li81fdadd2022-11-23 09:58:18 +0000251 tensors.add_const_tensor(ACL_SRC_1, wei);
SiCong Lif44bbc52022-08-29 18:25:51 +0100252 tensors.add_const_tensor(ACL_SRC_2, bia);
SiCong Li81fdadd2022-11-23 09:58:18 +0000253 tensors.add_const_tensor(ACL_DST_0, dst);
SiCong Lif44bbc52022-08-29 18:25:51 +0100254
255 const auto op = sketch.implementation().operator_group().new_operator(operator_type, tensors);
256 sketch.implementation().operator_group().add_operator(op);
Gunes Bayir3a1e1252023-01-03 21:26:09 +0000257
258 return dst;
SiCong Lif44bbc52022-08-29 18:25:51 +0100259}
260
261} // namespace dynamic_fusion
262} // namespace experimental
263} // namespace arm_compute