From a5cb79f18685292bf5b63a0c484a58945320823d Mon Sep 17 00:00:00 2001 From: Gian Marco Iodice Date: Wed, 28 Dec 2022 13:53:51 +0000 Subject: Update the ClConv2d heuristic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update the ClConv2d heuristic to call indirect convolution on Arm® Mali™-G77 Gpus - Implement the indirect conv2d heuristic for selecting the block size Resolves COMPMID-5713 Change-Id: If6ad49124561207153685c6abd4f54950a376fbc Signed-off-by: Gian Marco Iodice Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/8886 Benchmark: Arm Jenkins Tested-by: Arm Jenkins Reviewed-by: Gunes Bayir Comments-Addressed: Arm Jenkins --- src/gpu/cl/operators/ClConv2d.cpp | 45 +++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 7 deletions(-) (limited to 'src/gpu/cl/operators/ClConv2d.cpp') diff --git a/src/gpu/cl/operators/ClConv2d.cpp b/src/gpu/cl/operators/ClConv2d.cpp index 54e5d002da..51248d4a7a 100644 --- a/src/gpu/cl/operators/ClConv2d.cpp +++ b/src/gpu/cl/operators/ClConv2d.cpp @@ -23,15 +23,13 @@ */ #include "src/gpu/cl/operators/ClConv2d.h" -#include "arm_compute/core/PixelValue.h" -#include "arm_compute/core/Utils.h" #include "arm_compute/core/Validate.h" #include "arm_compute/core/utils/misc/ShapeCalculator.h" -#include "arm_compute/core/utils/quantization/AsymmHelpers.h" #include "arm_compute/runtime/CL/CLScheduler.h" #include "arm_compute/runtime/CL/functions/CLFFTConvolutionLayer.h" #include "src/gpu/cl/operators/ClDirectConv2d.h" #include "src/gpu/cl/operators/ClGemmConv2d.h" +#include "src/gpu/cl/operators/ClIndirectConv2d.h" #include "src/gpu/cl/operators/ClWinogradConv2d.h" #include "src/common/utils/Log.h" @@ -107,6 +105,15 @@ void ClConv2d::configure(const CLCompileContext &compile_context, ITensorInfo *s _operator = std::move(f); break; } + case ConvolutionMethod::INDIRECT: + { + ARM_COMPUTE_ERROR_ON(conv2d_info.num_groups != 1); + ARM_COMPUTE_ERROR_ON(conv2d_info.post_ops.size() > 0); + auto f = std::make_unique(); + f->configure(compile_context, src, weights, biases, dst, conv2d_info.conv_info, conv2d_info.act_info); + _operator = std::move(f); + break; + } case ConvolutionMethod::GEMM: { auto f = std::make_unique(); @@ -147,6 +154,14 @@ Status ClConv2d::validate(const ITensorInfo *src, const ITensorInfo *weights, co ARM_COMPUTE_RETURN_ON_ERROR(ClDirectConv2d::validate(src, weights, biases, dst, conv2d_info.conv_info, conv2d_info.act_info)); break; } + case ConvolutionMethod::INDIRECT: + { + // Validate indirect convolution layer + ARM_COMPUTE_RETURN_ERROR_ON_MSG(conv2d_info.num_groups != 1, "Grouping (num_groups != 1) with ClIndirectConv2d is not supported"); + ARM_COMPUTE_RETURN_ERROR_ON_MSG(conv2d_info.post_ops.size() > 0, "ClIndirectConv2d does not support PostOps"); + ARM_COMPUTE_RETURN_ON_ERROR(ClIndirectConv2d::validate(src, weights, biases, dst, conv2d_info.conv_info, conv2d_info.act_info)); + break; + } case ConvolutionMethod::GEMM: { // Validate gemm-based convolution layer @@ -266,6 +281,7 @@ ConvolutionMethod ClConv2d::get_convolution_method(const ITensorInfo *src, const const bool is_ifm_gt_ofm = src->dimension(idx_c) > weights->dimension(3U); const bool is_m_one = output_shape[1] * output_shape[2] == 1; const bool is_unit_stride = (conv2d_info.conv_info.stride().first == 1) && (conv2d_info.conv_info.stride().second == 1); + const int32_t kernel_sz = weights->dimension(idx_w) * weights->dimension(idx_h); // Run Winograd if valid and IFM >= 8 if(is_wino_valid && is_ifm_ge_8) @@ -302,25 +318,40 @@ ConvolutionMethod ClConv2d::get_convolution_method(const ITensorInfo *src, const } else { - // Direct convolution used for the first layer of the network + ConvolutionMethod preferred_conv_method = ConvolutionMethod::DIRECT; + + const bool is_indirect_valid = bool(ClIndirectConv2d::validate(src, weights, nullptr, dst, conv_info, act_info)); + + // indirect conv2d should be called when: + // 1- When the kernel size is greater than 1x1 and less than or equal to 9x9 (81) + // 2- When the kernel size is odd + // 3- When the Gpu target is Arm Mali-G77 + if(is_indirect_valid) + { + const bool is_kernel_sz_odd = kernel_sz % 2; + const bool is_g77 = gpu_target == GPUTarget::G77; + preferred_conv_method = (kernel_sz > 1) && (kernel_sz <= 81) && is_kernel_sz_odd && is_g77? ConvolutionMethod::INDIRECT : ConvolutionMethod::DIRECT; + } + + // Direct/indirect convolution used for the first layer of the network if(workload_gte_8192 && !is_ifm_ge_16 && !is_unit_stride && is_ofm_lt_64) { // In general, the question we should ask for the first convolution layer of a model is: // when the execution time of im2col + gemm < direct?. Since im2col does not depend on the OFM, it means that // when OFM is big enough, the contribution of im2col is small and the GEMM approach is preferable. // From internal experiments, the OFM threshold is 64 (is_ofm_lt_64) - return ConvolutionMethod::DIRECT; + return preferred_conv_method; } if((is_large_kernel_sz || is_m_one) && workload_gte_8192 && is_ifm_ge_16) { - return ConvolutionMethod::DIRECT; + return preferred_conv_method; } // Direct convolution used for the last layer of the network if(is_ofm_lte_8) { - return ConvolutionMethod::DIRECT; + return preferred_conv_method; } } } -- cgit v1.2.1