GitOrigin-RevId: 323bf6073a
tags/v1.2.0
| @@ -6,12 +6,13 @@ | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, | |||
| * software distributed under the License is distributed on an | |||
| * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or | |||
| * implied. | |||
| */ | |||
| #include "src/cuda/conv_bias/opr_impl.h" | |||
| #include "megdnn/dtype.h" | |||
| #include "src/cuda/conv_bias/helper.h" | |||
| #include "src/cuda/conv_bias/algo.h" | |||
| #include "src/cuda/conv_bias/helper.h" | |||
| #include "src/cuda/conv_bias/opr_impl.h" | |||
| #include "src/cuda/handle.h" | |||
| #include "src/cuda/utils.h" | |||
| @@ -124,6 +125,44 @@ ConvBiasForward::Algorithm* ConvBiasForwardImpl::get_algorithm_heuristic( | |||
| return nullptr; | |||
| }; | |||
| const bool is_chanwise = | |||
| (args.filter_meta.format == Param::Format::NCHW && | |||
| args.filter_meta.group == src[1]) || | |||
| (args.filter_meta.format == Param::Format::NCHW4 && | |||
| args.filter_meta.group == src[1] * 4) || | |||
| (args.filter_meta.format == Param::Format::NCHW32 && | |||
| args.filter_meta.group == src[1] * 32); | |||
| // prefer special chanwise impl since as the group conv of cudnn | |||
| // whose version is lower than v7.5.0 is still slower than our | |||
| // implementation in many channel-wise cases | |||
| const bool slow_cudnn_chanwise_impl = | |||
| CUDNN_MAJOR < 7 || (CUDNN_MAJOR == 7 && CUDNN_MINOR < 5); | |||
| //! choose CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_GEMM default for large image | |||
| const int hw_size = src[2] * src[3]; | |||
| //! choose dnn when stride != 1, may need calibrate for different cudnn | |||
| //! version | |||
| const bool prefer_dnn_chanwise = | |||
| slow_cudnn_chanwise_impl || args.filter_meta.stride[0] != 1 || | |||
| args.filter_meta.stride[1] != 1 || hw_size < 512; | |||
| //! avoid bad case in cudnn, check dnn chanwise impl first | |||
| if (is_chanwise) { | |||
| if (prefer_dnn_chanwise) { | |||
| if (sm_algo_pack.chanwise.is_available_reproducible( | |||
| args, reproducible, workspace_limit_in_bytes)) | |||
| return &sm_algo_pack.chanwise; | |||
| if (sm_algo_pack.chanwise8x8x32.is_available_reproducible( | |||
| args, reproducible, workspace_limit_in_bytes)) | |||
| return &sm_algo_pack.chanwise8x8x32; | |||
| } else { | |||
| conv_args.dst_layout = &dst_layout; | |||
| if (is_cudnn_supported(conv_args)) { | |||
| if (auto algo = get_cudnn_algo(cudnn_conv_from_enum_wrapper)) { | |||
| return algo; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| //! Prefer CUDNN CONVBIAS. | |||
| bool cudnn_conv_bias_act_supported = false; | |||
| for (auto&& algo : sm_algo_pack.cudnn_conv_bias_activations) { | |||
| @@ -139,22 +178,10 @@ ConvBiasForward::Algorithm* ConvBiasForwardImpl::get_algorithm_heuristic( | |||
| return algo; | |||
| } | |||
| if (args.filter_meta.group > 1) { | |||
| #if CUDNN_MAJOR < 7 || (CUDNN_MAJOR == 7 && CUDNN_MINOR < 5) | |||
| // prefer special chanwise impl since as the group conv of cudnn whose | |||
| // version is lower than v7.5.0 is still slower than our implementation | |||
| // in many channel-wise cases | |||
| if (sm_algo_pack.chanwise.is_available_reproducible( | |||
| args, reproducible, workspace_limit_in_bytes)) | |||
| return &sm_algo_pack.chanwise; | |||
| if (sm_algo_pack.chanwise8x8x32.is_available_reproducible( | |||
| args, reproducible, workspace_limit_in_bytes)) | |||
| return &sm_algo_pack.chanwise8x8x32; | |||
| #endif | |||
| } | |||
| if (auto algo = get_1x1_algo(args)) { | |||
| return algo; | |||
| int batch = src[0]; | |||
| if (batch == 1 && sm_algo_pack.a1x1.is_available_reproducible( | |||
| args, reproducible, workspace_limit_in_bytes)) { | |||
| return &sm_algo_pack.a1x1; | |||
| } | |||
| // modify conv_args dst_layout | |||
| @@ -179,6 +206,10 @@ ConvBiasForward::Algorithm* ConvBiasForwardImpl::get_algorithm_heuristic( | |||
| conv_args = orig_args; | |||
| } | |||
| if (auto algo = get_1x1_algo(args)) { | |||
| return algo; | |||
| } | |||
| if (args.src_layout->dtype.enumv() != DTypeTrait<dtype::BFloat16>::enumv) { | |||
| if (reproducible) { | |||
| return megdnn::get_reproducible_algo<ConvBiasForwardImpl>( | |||
| @@ -839,6 +839,88 @@ TEST_F(CUDA, BENCHMARK_CHANWISE_CONV_FORWARD_FLOAT_SMALL) { | |||
| } | |||
| TEST_F(CUDA, BENCHMARK_CHANWISE_CONV_FORWARD_CUDNN_DNN) { | |||
| CUBenchmarker<ConvBiasForward> bencher(handle_cuda()); | |||
| size_t RUNS = 1; | |||
| bencher.set_display(false).set_times(RUNS); | |||
| ConvBias::Param param; | |||
| param.format = ConvBias::Param::Format::NCHW; | |||
| param.sparse = ConvBias::Param::Sparse::GROUP; | |||
| NormalRNG rng; | |||
| auto run = [&](size_t batch, size_t c, size_t ih, size_t iw, size_t f, | |||
| size_t s) { | |||
| param.pad_h = f / 2; | |||
| param.pad_w = f / 2; | |||
| param.stride_h = s; | |||
| param.stride_w = s; | |||
| param.compute_mode = param::ConvBias::ComputeMode::DEFAULT; | |||
| TensorShape src = {batch, c, ih, iw}, filter = {c, 1, 1, f, f}, | |||
| bias = {1, c, 1, 1}; | |||
| TensorLayout dst_layout; | |||
| auto opr = handle_cuda()->create_operator<ConvBias>(); | |||
| opr->param() = param; | |||
| opr->deduce_layout({src, dtype::Float32()}, {filter, dtype::Float32()}, | |||
| {bias, dtype::Float32()}, {}, dst_layout); | |||
| float computation_mops = | |||
| static_cast<float>(dst_layout.total_nr_elems() * f * f * 2) * | |||
| 1e-6; | |||
| bencher.set_param(param) | |||
| .set_dtype(0, dtype::Float32()) | |||
| .set_dtype(1, dtype::Float32()) | |||
| .set_dtype(2, dtype::Float32()) | |||
| .set_rng(0, &rng) | |||
| .set_rng(1, &rng); | |||
| bencher.set_before_exec_callback( | |||
| AlgoChecker<ConvBiasForward>(".+CHANNEL_WISE.+")); | |||
| auto time_in_ms_dnn = bencher.execs({src, filter, bias, {}, {}}) / RUNS; | |||
| bencher.set_param(param) | |||
| .set_dtype(0, dtype::Float32()) | |||
| .set_dtype(1, dtype::Float32()) | |||
| .set_dtype(2, dtype::Float32()) | |||
| .set_rng(0, &rng) | |||
| .set_rng(1, &rng); | |||
| bencher.set_before_exec_callback(AlgoChecker<ConvBiasForward>( | |||
| ".+CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_GEMM.+")); | |||
| auto time_in_ms_cudnn = | |||
| bencher.execs({src, filter, bias, {}, {}}) / RUNS; | |||
| printf("stride=%zu src=%s, filter=%s, dst=%s, dnn: %.2fms %.2fGB/s " | |||
| "cudnn: %.2fms %.2fGB/s " | |||
| "speedup: " | |||
| "%0.2f (dnn/cudnn)\n", | |||
| s, src.to_string().c_str(), filter.to_string().c_str(), | |||
| dst_layout.to_string().c_str(), time_in_ms_dnn, | |||
| computation_mops / time_in_ms_dnn, time_in_ms_cudnn, | |||
| computation_mops / time_in_ms_cudnn, | |||
| time_in_ms_cudnn / time_in_ms_dnn); | |||
| }; | |||
| // clang-format off | |||
| for(size_t batch:{1, 16, 32, 64, 128}){ | |||
| run(batch, 32, 112, 112, 3, 1); | |||
| run(batch, 96, 112, 112, 3, 2); | |||
| run(batch, 96, 112, 112, 3, 1); | |||
| run(batch, 144, 56, 56, 3, 2); | |||
| run(batch, 144, 56, 56, 3, 1); | |||
| run(batch, 192, 28, 28, 3, 1); | |||
| run(batch, 384, 14, 14, 3, 1); | |||
| run(batch, 576, 14, 14, 3, 1); | |||
| run(batch, 960, 7, 7, 3, 1); | |||
| //! calibrate heu algo policy hw_size param | |||
| run(batch, 144, 24, 24, 3, 1); | |||
| run(batch, 144, 22, 22, 3, 1); | |||
| run(batch, 144, 20, 20, 3, 1); | |||
| run(batch, 144, 18, 18, 3, 1); | |||
| } | |||
| // clang-format on | |||
| } | |||
| TEST_F(CUDA, BENCHMARK_CHANWISE_CONV_BACKWARD_DATA_FLOAT_SMALL) { | |||
| CUBenchmarker<ConvolutionBackwardData> bencher(handle_cuda()); | |||
| size_t RUNS = 1; | |||