Skip to content

Commit 37cb085

Browse files
authored
[OpenCL][kernel]add depthwise transpose conv opencl op and ut (#6816)
* add depthwise transpose conv op test=develop * add depthwise transpose conv op test=develop * add depthwise transpose conv op test=develop
1 parent 40b8c9e commit 37cb085

4 files changed

Lines changed: 441 additions & 11 deletions

File tree

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/* Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License. */
14+
15+
#include "cl_common.h"
16+
17+
__kernel void depthwise_conv2d_transpose(
18+
__private const int global_size_dim0, // (out_c + 3) / 4
19+
__private const int global_size_dim1, // out_w
20+
__private const int global_size_dim2, // out_n * out_h
21+
__read_only image2d_t input,
22+
__read_only image2d_t filter,
23+
__read_only image2d_t bias,
24+
__write_only image2d_t output,
25+
__private const int2 input_shape,
26+
__private const int2 output_shape,
27+
__private const int2 stride_shape,
28+
__private const int2 align_shape,
29+
__private const int2 padding_shape,
30+
__private const int2 kernel_shape,
31+
__private const int kernel_size,
32+
__private const int input_c_blks) {
33+
const int out_c_blk_idx = get_global_id(0);
34+
const int out_w_idx = get_global_id(1);
35+
const int out_nh_idx = get_global_id(2);
36+
37+
if (out_c_blk_idx >= global_size_dim0 || out_w_idx >= global_size_dim1 ||
38+
out_nh_idx >= global_size_dim2) {
39+
return;
40+
}
41+
42+
const int out_n_idx = out_nh_idx / output_shape.y;
43+
const int out_h_idx = out_nh_idx % output_shape.y;
44+
45+
int kernel_start_x = max(0, (out_w_idx + align_shape.x) / stride_shape.x);
46+
int kernel_start_y = max(0, (out_h_idx + align_shape.y) / stride_shape.y);
47+
int valid_kernel_width =
48+
kernel_shape.x - mad24(kernel_start_x, stride_shape.x, padding_shape.x) +
49+
out_w_idx - 1;
50+
int valid_kernel_height =
51+
kernel_shape.y - mad24(kernel_start_y, stride_shape.y, padding_shape.y) +
52+
out_h_idx - 1;
53+
54+
int kernel_x_0, kernel_x_1, kernel_x_2, kernel_x_3, kernel_y;
55+
CL_DTYPE4 in0;
56+
CL_DTYPE4 weights0, weights1, weights2, weights3;
57+
int ic = out_c_blk_idx;
58+
59+
#ifdef BIASE_CH
60+
CL_DTYPE4 out0 =
61+
READ_IMG_TYPE(CL_DTYPE_CHAR, bias, SAMPLER, (int2)(out_c_blk_idx, 0));
62+
#else
63+
CL_DTYPE4 out0 = 0.f;
64+
#endif
65+
kernel_x_0 = ic << 2;
66+
kernel_x_1 = kernel_x_0 + 1;
67+
kernel_x_2 = kernel_x_0 + 2;
68+
kernel_x_3 = kernel_x_0 + 3;
69+
int in_idx = mul24(ic, input_shape.x);
70+
for (int k_y = valid_kernel_height, idx_h = kernel_start_y; k_y >= 0;
71+
k_y -= stride_shape.y, idx_h++) {
72+
int in_y_idx = mad24(out_n_idx, input_shape.y, idx_h);
73+
int in_nh_value = select(in_y_idx, -1, idx_h < 0 || idx_h >= input_shape.y);
74+
int in_width0 = kernel_start_x;
75+
76+
for (int k_x = valid_kernel_width; k_x >= 0; k_x -= stride_shape.x) {
77+
kernel_y = mad24(k_y, kernel_shape.x, k_x);
78+
79+
weights0 = READ_IMG_TYPE(
80+
CL_DTYPE_CHAR, filter, SAMPLER, (int2)(kernel_x_0, kernel_y));
81+
weights1 = READ_IMG_TYPE(
82+
CL_DTYPE_CHAR, filter, SAMPLER, (int2)(kernel_x_1, kernel_y));
83+
weights2 = READ_IMG_TYPE(
84+
CL_DTYPE_CHAR, filter, SAMPLER, (int2)(kernel_x_2, kernel_y));
85+
weights3 = READ_IMG_TYPE(
86+
CL_DTYPE_CHAR, filter, SAMPLER, (int2)(kernel_x_3, kernel_y));
87+
88+
int in_width_value0 = in_width0;
89+
in_width_value0 =
90+
select(in_idx + in_width_value0,
91+
-1,
92+
(in_width_value0 < 0 || in_width_value0 >= input_shape.x));
93+
in0 = READ_IMG_TYPE(
94+
CL_DTYPE_CHAR, input, SAMPLER, (int2)(in_width_value0, in_nh_value));
95+
96+
out0.x += in0.x * weights0.x;
97+
out0.y += in0.y * weights1.x;
98+
out0.z += in0.z * weights2.x;
99+
out0.w += in0.w * weights3.x;
100+
in_width0++;
101+
}
102+
}
103+
int2 out_pos0 =
104+
(int2)(out_c_blk_idx * output_shape.x + out_w_idx, out_nh_idx);
105+
out0 = activation_type4(out0, 0.f);
106+
#ifdef SCALE_ACTIVATION
107+
out0 = fuse_scale(out0, 1.f, 0.f, 0.f);
108+
#endif
109+
WRITE_IMG_TYPE(CL_DTYPE_CHAR, output, out_pos0, out0);
110+
}

lite/kernels/opencl/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ lite_cc_test(test_depthwise_conv2d_image_opencl SRCS depthwise_conv2d_image_comp
6565
lite_cc_test(test_conv_transpose_image_opencl SRCS conv_transpose_image_compute_test.cc
6666
DEPS conv_transpose_opencl_image core)
6767

68+
lite_cc_test(test_depthwise_conv2d_transpose_image_opencl SRCS depthwise_conv2d_transpose_image_compute_test.cc
69+
DEPS conv_transpose_opencl_image core)
70+
6871
lite_cc_test(test_nearest_interp_image_opencl SRCS nearest_interp_image_compute_test.cc
6972
DEPS nearest_interp_opencl_image layout_opencl_image core)
7073

lite/kernels/opencl/conv_transpose_image_compute.cc

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,18 @@ void ConvTransposeImageCompute::PrepareForRun() {
2727
const bool is_mali = context.cl_context()->IsArmMali();
2828

2929
conv_param_ = param_.get_mutable<param_t>();
30+
auto x_dims = conv_param_->x->dims();
31+
input_tensor_n_ = x_dims[0];
32+
input_tensor_c_ = x_dims[1];
33+
input_tensor_h_ = x_dims[2];
34+
input_tensor_w_ = x_dims[3];
35+
36+
auto output_dims = conv_param_->output->dims();
37+
output_tensor_n_ = output_dims[0];
38+
output_tensor_c_ = output_dims[1];
39+
output_tensor_h_ = output_dims[2];
40+
output_tensor_w_ = output_dims[3];
41+
3042
auto filter_dims = conv_param_->filter->dims();
3143
filter_tensor_c_ = filter_dims[1];
3244
filter_tensor_h_ = filter_dims[2];
@@ -56,14 +68,14 @@ void ConvTransposeImageCompute::PrepareForRun() {
5668
std::vector<float> filter_cpu_trans(conv_param_->filter->numel());
5769
DDimLite filter_trans_dims{
5870
{filter_dims[1], filter_dims[0], filter_dims[2], filter_dims[3]}};
71+
5972
// Convert filter layout from IOHW to OIHW
6073
IOHW2OIHW<float, int64_t>(filter_cpu,
6174
filter_cpu_trans.data(),
6275
filter_trans_dims[0],
6376
filter_trans_dims[1],
6477
filter_trans_dims[2],
6578
filter_trans_dims[3]);
66-
6779
filter_gpu_image_ = std::unique_ptr<Tensor>(new Tensor);
6880
tensor_hold_filter_image_ = std::unique_ptr<Tensor>(new Tensor);
6981
tensor_hold_bias_image_ = std::unique_ptr<Tensor>(new Tensor);
@@ -72,6 +84,23 @@ void ConvTransposeImageCompute::PrepareForRun() {
7284
std::string kernel_name = "conv2d_transpose";
7385
kernel_func_names_.push_back(kernel_name);
7486

87+
CLImageConverterNBlock converter;
88+
const DDim& filter_image_dims =
89+
converter.InitImageDimInfoWith(filter_trans_dims);
90+
filter_image_w_ = filter_image_dims[0]; // ((C + 3) / 4) * 4;
91+
filter_image_h_ = filter_image_dims[1]; // ((N + 3) / 4) * H * W;
92+
tensor_hold_filter_image_->Resize({1, filter_image_w_, filter_image_h_, 4});
93+
auto* filter_image_data = MUTABLE_DATA_CPU(tensor_hold_filter_image_);
94+
95+
converter.NCHWToImage(
96+
filter_cpu_trans.data(), filter_image_data, filter_trans_dims);
97+
MUTABLE_DATA_GPU(
98+
filter_gpu_image_, filter_image_w_, filter_image_h_, filter_image_data);
99+
} else if ((groups_ == input_tensor_c_) && (groups_ == output_tensor_c_)) {
100+
// for depthwsie conv transpose
101+
std::string kernel_name = "depthwise_conv2d_transpose";
102+
kernel_func_names_.push_back(kernel_name);
103+
75104
CLImageConverterNBlock converter;
76105
const DDim& filter_image_dims =
77106
converter.InitImageDimInfoWith(filter_trans_dims);
@@ -86,7 +115,8 @@ void ConvTransposeImageCompute::PrepareForRun() {
86115
filter_gpu_image_, filter_image_w_, filter_image_h_, filter_image_data);
87116
} else {
88117
LOG(FATAL)
89-
<< "conv2d_transpose image compute not support this condition yet!";
118+
<< "conv2d_transpose image compute not support this condition yet! "
119+
<< groups_ << " " << input_tensor_c_ << " " << output_tensor_c_;
90120
}
91121

92122
// build options
@@ -180,7 +210,11 @@ void ConvTransposeImageCompute::PrepareForRun() {
180210
<< conv_param_->scale_activation_type;
181211
}
182212

183-
kernel_func_paths_.push_back("image/conv2d_transpose_kernel.cl");
213+
if (groups_ == 1) {
214+
kernel_func_paths_.push_back("image/conv2d_transpose_kernel.cl");
215+
} else if ((groups_ == input_tensor_c_) && (groups_ == output_tensor_c_)) {
216+
kernel_func_paths_.push_back("image/depthwise_conv2d_transpose_kernel.cl");
217+
}
184218
VLOG(1) << "kernel_func_names_[0]:" << kernel_func_names_[0]
185219
<< " kernel_func_paths_[0]:" << kernel_func_paths_[0];
186220
build_options_.push_back(build_options_single);
@@ -209,19 +243,11 @@ void ConvTransposeImageCompute::ReInitWhenNeeded() {
209243
is_first_epoch_for_run_ = false;
210244
last_input_dims_ = x_dims;
211245

212-
input_tensor_n_ = x_dims[0];
213-
input_tensor_c_ = x_dims[1];
214-
input_tensor_h_ = x_dims[2];
215-
input_tensor_w_ = x_dims[3];
216246
auto x_image_shape = InitImageDimInfoWith(x_dims);
217247
input_image_h_ = x_image_shape["height"];
218248
input_image_w_ = x_image_shape["width"];
219249

220250
auto output_dims = conv_param_->output->dims();
221-
output_tensor_n_ = output_dims[0];
222-
output_tensor_c_ = output_dims[1];
223-
output_tensor_h_ = output_dims[2];
224-
output_tensor_w_ = output_dims[3];
225251
auto output_image_shape = InitImageDimInfoWith(output_dims);
226252
output_image_h_ = output_image_shape["height"];
227253
output_image_w_ = output_image_shape["width"];
@@ -247,13 +273,17 @@ void ConvTransposeImageCompute::SetGlobalWorkSize() {
247273
global_work_size_ = cl::NDRange{static_cast<size_t>(gws[0]),
248274
static_cast<size_t>(gws[1]),
249275
static_cast<size_t>(gws[2])};
276+
LOG(INFO) << "global_work_size_: " << gws[0] << " " << gws[1] << " "
277+
<< gws[2];
250278
}
251279

252280
void ConvTransposeImageCompute::SetArgs() {
253281
const int pad_w = filter_tensor_w_ - 1 - pad_left_;
254282
const int pad_h = filter_tensor_h_ - 1 - pad_up_;
255283
const int align_w = stride_w_ - 1 - pad_w;
256284
const int align_h = stride_h_ - 1 - pad_h;
285+
LOG(INFO) << "pad_w, pad_h: " << pad_w << " " << pad_h;
286+
LOG(INFO) << "align_w, align_h: " << align_w << " " << align_h;
257287
cl_int2 pad_wh = {pad_w, pad_h};
258288
cl_int2 align_wh = {align_w, align_h};
259289

@@ -371,3 +401,22 @@ REGISTER_LITE_KERNEL(conv2d_transpose,
371401
DATALAYOUT(kImageDefault))})
372402
.BindPaddleOpVersion("conv2d_transpose", 1)
373403
.Finalize();
404+
405+
REGISTER_LITE_KERNEL(depthwise_conv2d_transpose,
406+
kOpenCL,
407+
kFP16,
408+
kImageDefault,
409+
paddle::lite::kernels::opencl::ConvTransposeImageCompute,
410+
image2d)
411+
.BindInput("Input",
412+
{LiteType::GetTensorTy(TARGET(kOpenCL),
413+
PRECISION(kFP16),
414+
DATALAYOUT(kImageDefault))})
415+
.BindInput("Bias", {LiteType::GetTensorTy(TARGET(kARM))})
416+
.BindInput("Filter", {LiteType::GetTensorTy(TARGET(kARM))})
417+
.BindOutput("Output",
418+
{LiteType::GetTensorTy(TARGET(kOpenCL),
419+
PRECISION(kFP16),
420+
DATALAYOUT(kImageDefault))})
421+
.BindPaddleOpVersion("depthwise_conv2d_transpose", 1)
422+
.Finalize();

0 commit comments

Comments
 (0)