From 74276314bb1b8b6af070f68c1939c38b944cf257 Mon Sep 17 00:00:00 2001 From: nihuini Date: Wed, 29 May 2019 20:11:37 +0800 Subject: [PATCH] unroll size 4 for conv1x1s1 pack4 --- src/layer/vulkan/convolution_vulkan.cpp | 65 ++++++-- src/layer/vulkan/convolution_vulkan.h | 1 + .../shader/convolution_pack4_1x1s1d1.comp | 155 ++++++++++++++++++ 3 files changed, 207 insertions(+), 14 deletions(-) create mode 100644 src/layer/vulkan/shader/convolution_pack4_1x1s1d1.comp diff --git a/src/layer/vulkan/convolution_vulkan.cpp b/src/layer/vulkan/convolution_vulkan.cpp index d54f3cef8..345896a23 100644 --- a/src/layer/vulkan/convolution_vulkan.cpp +++ b/src/layer/vulkan/convolution_vulkan.cpp @@ -29,6 +29,7 @@ Convolution_vulkan::Convolution_vulkan() pipeline_convolution = 0; pipeline_convolution_1x1s1d1 = 0; pipeline_convolution_pack4 = 0; + pipeline_convolution_pack4_1x1s1d1 = 0; pipeline_convolution_pack4_3x3s1d1_lds_8_8_2 = 0; winograd23_padding = 0; winograd23_crop = 0; @@ -63,20 +64,6 @@ int Convolution_vulkan::create_pipeline(const Option& opt) padding->create_pipeline(opt); } - if (kernel_w == 1 && kernel_h == 1 && stride_w == 1 && stride_h == 1 && dilation_w == 1 && dilation_h == 1) - { - pipeline_convolution_1x1s1d1 = new Pipeline(vkdev); - pipeline_convolution_1x1s1d1->set_optimal_local_size_xyz(-1, 1, std::max(1, num_output / 8)); - - std::vector specializations(4); - specializations[0].i = bias_term; - specializations[1].i = activation_type; - specializations[2].f = activation_params.w == 1 ? activation_params[0] : 0.f; - specializations[3].f = activation_params.w == 2 ? activation_params[1] : 0.f; - - pipeline_convolution_1x1s1d1->create("convolution_1x1s1d1", specializations, 4, 8); - } - const int maxk = kernel_w * kernel_h; int num_input = weight_data_size / maxk / num_output; @@ -98,6 +85,20 @@ int Convolution_vulkan::create_pipeline(const Option& opt) pipeline_convolution = new Pipeline(vkdev); pipeline_convolution->set_optimal_local_size_xyz(32, 32, std::max(1, num_output / 8)); pipeline_convolution->create("convolution", specializations, 4, 10); + + if (kernel_w == 1 && kernel_h == 1 && stride_w == 1 && stride_h == 1 && dilation_w == 1 && dilation_h == 1) + { + pipeline_convolution_1x1s1d1 = new Pipeline(vkdev); + pipeline_convolution_1x1s1d1->set_optimal_local_size_xyz(-1, 1, std::max(1, num_output / 8)); + + std::vector specializations(4); + specializations[0].i = bias_term; + specializations[1].i = activation_type; + specializations[2].f = activation_params.w == 1 ? activation_params[0] : 0.f; + specializations[3].f = activation_params.w == 2 ? activation_params[1] : 0.f; + + pipeline_convolution_1x1s1d1->create("convolution_1x1s1d1", specializations, 4, 8); + } } // pack4 @@ -107,6 +108,20 @@ int Convolution_vulkan::create_pipeline(const Option& opt) pipeline_convolution_pack4->set_optimal_local_size_xyz(32, 32, std::max(1, num_output / 8)); pipeline_convolution_pack4->create("convolution_pack4", specializations, 4, 10); + if (kernel_w == 1 && kernel_h == 1 && stride_w == 1 && stride_h == 1 && dilation_w == 1 && dilation_h == 1) + { + pipeline_convolution_pack4_1x1s1d1 = new Pipeline(vkdev); + pipeline_convolution_pack4_1x1s1d1->set_local_size_xyz(8, 1, std::min(8, num_output / 2)); + + std::vector specializations(4); + specializations[0].i = bias_term; + specializations[1].i = activation_type; + specializations[2].f = activation_params.w == 1 ? activation_params[0] : 0.f; + specializations[3].f = activation_params.w == 2 ? activation_params[1] : 0.f; + + pipeline_convolution_pack4_1x1s1d1->create("convolution_pack4_1x1s1d1", specializations, 4, 8); + } + if (kernel_w == 3 && kernel_h == 3 && stride_w == 1 && stride_h == 1 && dilation_w == 1 && dilation_h == 1) { std::vector specializations(4); @@ -249,6 +264,9 @@ int Convolution_vulkan::destroy_pipeline(const Option& opt) delete pipeline_convolution_pack4; pipeline_convolution_pack4 = 0; + delete pipeline_convolution_pack4_1x1s1d1; + pipeline_convolution_pack4_1x1s1d1 = 0; + delete pipeline_convolution_pack4_3x3s1d1_lds_8_8_2; pipeline_convolution_pack4_3x3s1d1_lds_8_8_2 = 0; @@ -929,6 +947,25 @@ int Convolution_vulkan::forward(const VkMat& bottom_blob, VkMat& top_blob, VkCom cmd.record_pipeline(pipeline_convolution_1x1s1d1, bindings, constants, dispatcher); } + else if (packing == 4 && out_packing == 4 && kernel_w == 1 && kernel_h == 1 && stride_w == 1 && stride_h == 1 && dilation_w == 1 && dilation_h == 1) + { + std::vector constants(8); + constants[0].i = bottom_blob_bordered.dims; + constants[1].i = (bottom_blob_bordered.cstep + 3) / 4; + constants[2].i = bottom_blob_bordered.c; + constants[3].i = bottom_blob_bordered.cstep; + constants[4].i = top_blob.dims; + constants[5].i = (top_blob.cstep + 3) / 4; + constants[6].i = top_blob.c; + constants[7].i = top_blob.cstep; + + VkMat dispatcher; + dispatcher.w = (top_blob.cstep + 3) / 4; + dispatcher.h = 1; + dispatcher.c = top_blob.c; + + cmd.record_pipeline(pipeline_convolution_pack4_1x1s1d1, bindings, constants, dispatcher); + } else if (packing == 4 && out_packing == 4 && kernel_w == 3 && kernel_h == 3 && stride_w == 1 && stride_h == 1 && dilation_w == 1 && dilation_h == 1) { std::vector constants(10); diff --git a/src/layer/vulkan/convolution_vulkan.h b/src/layer/vulkan/convolution_vulkan.h index 6b7078cec..0a62b48c0 100644 --- a/src/layer/vulkan/convolution_vulkan.h +++ b/src/layer/vulkan/convolution_vulkan.h @@ -45,6 +45,7 @@ public: // pack4 VkMat weight_data_gpu_pack4; Pipeline* pipeline_convolution_pack4; + Pipeline* pipeline_convolution_pack4_1x1s1d1; Pipeline* pipeline_convolution_pack4_3x3s1d1_lds_8_8_2; // pack4 winograd23 diff --git a/src/layer/vulkan/shader/convolution_pack4_1x1s1d1.comp b/src/layer/vulkan/shader/convolution_pack4_1x1s1d1.comp new file mode 100644 index 000000000..adff388c7 --- /dev/null +++ b/src/layer/vulkan/shader/convolution_pack4_1x1s1d1.comp @@ -0,0 +1,155 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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. + +#version 450 + +#if NCNN_fp16_storage +#extension GL_EXT_shader_16bit_storage: require +#endif +#if NCNN_fp16_arithmetic +#extension GL_AMD_gpu_shader_half_float: require +#endif + +layout (constant_id = 0) const int bias_term = 0; +layout (constant_id = 1) const int activation_type = 0; +layout (constant_id = 2) const float activation_param_0 = 0; +layout (constant_id = 3) const float activation_param_1 = 0; + +layout (local_size_x_id = 233) in; +layout (local_size_y_id = 234) in; +layout (local_size_z_id = 235) in; + +layout (binding = 0) readonly buffer bottom_blob { sfpvec4 bottom_blob_data[]; }; +layout (binding = 1) writeonly buffer top_blob { sfpvec4 top_blob_data[]; }; +#if NCNN_fp16_packed || (NCNN_fp16_storage && !NCNN_fp16_arithmetic) +// GL_EXT_shader_16bit_storage does not define f16mat4 type :( +layout (binding = 2) readonly buffer weight_blob { sfpvec4 weight_data[]; }; +#else +layout (binding = 2) readonly buffer weight_blob { sfpmat4 weight_data[]; }; +#endif +layout (binding = 3) readonly buffer bias_blob { sfpvec4 bias_data[]; }; + +layout (push_constant) uniform parameter +{ + int dims; + int size_4; + int c; + int cstep; + + int outdims; + int outsize_4; + int outc; + int outcstep; +} p; + +void main() +{ + int gx = int(gl_GlobalInvocationID.x); + int gy = int(gl_GlobalInvocationID.y); + int gz = int(gl_GlobalInvocationID.z); + + if (gx >= p.outsize_4 || gy >= 1 || gz >= p.outc) + return; + + afpvec4 sum0; + afpvec4 sum1; + afpvec4 sum2; + afpvec4 sum3; + + if (bias_term == 1) + { + afpvec4 b = sfp2afpvec4(bias_data[gz]); + sum0 = b; + sum1 = b; + sum2 = b; + sum3 = b; + } + else + { + sum0 = afpvec4(0.f); + sum1 = afpvec4(0.f); + sum2 = afpvec4(0.f); + sum3 = afpvec4(0.f); + } + + int w_offset = gz * p.c; + int v_offset = gx * 4; + + for (int z = 0; z < p.c; z++) + { + afpvec4 v0 = sfp2afpvec4(bottom_blob_data[v_offset + 0]); + afpvec4 v1 = sfp2afpvec4(bottom_blob_data[v_offset + 1]); + afpvec4 v2 = sfp2afpvec4(bottom_blob_data[v_offset + 2]); + afpvec4 v3 = sfp2afpvec4(bottom_blob_data[v_offset + 3]); + +#if NCNN_fp16_packed || (NCNN_fp16_storage && !NCNN_fp16_arithmetic) + // GL_EXT_shader_16bit_storage does not define f16mat4 type :( + afpmat4 k = afpmat4( + sfp2afpvec4(weight_data[w_offset * 4 + 0]), + sfp2afpvec4(weight_data[w_offset * 4 + 1]), + sfp2afpvec4(weight_data[w_offset * 4 + 2]), + sfp2afpvec4(weight_data[w_offset * 4 + 3]) + ); +#else + afpmat4 k = sfp2afpmat4(weight_data[w_offset]); +#endif + + sum0 += v0 * k; + sum1 += v1 * k; + sum2 += v2 * k; + sum3 += v3 * k; + + w_offset += 1; + v_offset += p.cstep; + } + + if (activation_type == 1) + { + sum0 = max(sum0, afp(0.f)); + sum1 = max(sum1, afp(0.f)); + sum2 = max(sum2, afp(0.f)); + sum3 = max(sum3, afp(0.f)); + } + if (activation_type == 2) + { + const afp slope = afp(activation_param_0); + sum0 = mix(sum0, sum0 * afp(slope), lessThan(sum0, afpvec4(0.f))); + sum1 = mix(sum1, sum1 * afp(slope), lessThan(sum1, afpvec4(0.f))); + sum2 = mix(sum2, sum2 * afp(slope), lessThan(sum2, afpvec4(0.f))); + sum3 = mix(sum3, sum3 * afp(slope), lessThan(sum3, afpvec4(0.f))); + } + if (activation_type == 3) + { + const afp const_min = afp(activation_param_0); + const afp const_max = afp(activation_param_1); + sum0 = clamp(sum0, const_min, const_max); + sum1 = clamp(sum1, const_min, const_max); + sum2 = clamp(sum2, const_min, const_max); + sum3 = clamp(sum3, const_min, const_max); + } + if (activation_type == 4) + { + sum0 = afp(1.f) / (afp(1.f) + exp(-sum0)); + sum1 = afp(1.f) / (afp(1.f) + exp(-sum1)); + sum2 = afp(1.f) / (afp(1.f) + exp(-sum2)); + sum3 = afp(1.f) / (afp(1.f) + exp(-sum3)); + } + + int gi = gz * p.outcstep + gx * 4; + + top_blob_data[gi + 0] = afp2sfpvec4(sum0); + if (gx * 4 + 1 < p.outcstep) top_blob_data[gi + 1] = afp2sfpvec4(sum1); + if (gx * 4 + 2 < p.outcstep) top_blob_data[gi + 2] = afp2sfpvec4(sum2); + if (gx * 4 + 3 < p.outcstep) top_blob_data[gi + 3] = afp2sfpvec4(sum3); +}