| @@ -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<vk_specialization_type> 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<vk_specialization_type> 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<vk_specialization_type> 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<vk_specialization_type> 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<vk_constant_type> 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<vk_constant_type> constants(10); | |||
| @@ -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 | |||
| @@ -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); | |||
| } | |||