diff --git a/src/fpga/V1/api.cpp b/src/fpga/V1/api.cpp index ef7d5c13dce50706d69b28830d8c23748266b216..efcc9f742e88e9a96394a2f6a15118c918624515 100644 --- a/src/fpga/V1/api.cpp +++ b/src/fpga/V1/api.cpp @@ -14,6 +14,7 @@ limitations under the License. */ #include "fpga/V1/api.h" #include "fpga/V1/bias_scale.h" +#include "fpga/V1/deconv_filter.h" #include "fpga/V1/filter.h" #include "fpga/V1/image.h" @@ -124,6 +125,32 @@ void format_fc_filter(framework::Tensor *filter_tensor, float max_value) { max_value); filter_tensor->reset_data_ptr(new_data); } +void format_deconv_filter(framework::Tensor *filter_tensor, float max_value, + int group_num, int stride) { + filter_tensor->scale[0] = float(max_value / 127.0); // NOLINT + filter_tensor->scale[1] = float(127.0 / max_value); // NOLINT + auto dims = filter_tensor->dims(); + auto num = dims[0], channel = dims[1], height = dims[2], width = dims[3]; + auto data_ptr = filter_tensor->data(); + size_t memory_size = num * channel * height * width * sizeof(float); + auto new_data = (float *)fpga_malloc(memory_size); // NOLINT + memcpy(new_data, data_ptr, memory_size); + + int hw = height * width; + deconv_filter::deconv_NC_convert(&new_data, num, channel, hw); + + num = dims[1]; + channel = dims[0]; + deconv_filter::deconv_format_filter( + &new_data, (int)num, (int)channel, // NOLINT + (int)height, // NOLINT + (int)width, group_num, max_value, stride); // NOLINT + + framework::DDim dims_new = + framework::make_ddim({num, channel, height, width}); + filter_tensor->Resize(dims_new); + filter_tensor->reset_data_ptr(new_data); +} void format_bias_scale_array(float **bias_scale_array, int element_num_per_division, int num) { @@ -240,6 +267,100 @@ void fill_split_arg(struct SplitConvArgs *arg, framework::Tensor *input, filter->reset_data_ptr(nullptr); fpga_free(bs_ptr); } +void fill_deconv_arg(struct DeconvArgs *arg, framework::Tensor *input, + framework::Tensor *out, framework::Tensor *filter, + bool relu_enabled, int group_num, int stride_h, + int stride_w, int padding_h, int padding_w, + float *bs_ptr) { + auto input_ptr = input->data(); + auto filter_ptr = filter->data(); + auto out_ptr = out->data(); + + arg->group_num = (uint32_t)group_num; + arg->sub_conv_num = stride_h; + arg->filter_num = (uint32_t)filter->dims()[0]; + + int sub_conv_num = arg->sub_conv_num; + int sub_stride = 1; + int sub_pad = deconv_filter::deconv_calc_sub_pad(filter->dims()[3], padding_w, + stride_w); + int sub_filter_width = + deconv_filter::deconv_get_sub_filter_axis(filter->dims()[3], stride_w); + int sub_output_width = deconv_filter::deconv_get_sub_out_axis( + input->dims()[3], sub_pad, sub_filter_width); + int sub_output_height = deconv_filter::deconv_get_sub_out_axis( + input->dims()[2], sub_pad, sub_filter_width); + + arg->sub_output_width = sub_output_width; + arg->sub_output_height = sub_output_height; + arg->omit_size = + deconv_filter::deconv_get_omit(stride_w, filter->dims()[3], padding_w); + arg->conv_args = (ConvArgs *)fpga_malloc(sub_conv_num * sizeof(ConvArgs)); + + int sub_channels = (int32_t)input->dims()[1]; + int omit_size = arg->omit_size; + int real_out_width = sub_output_width * sub_conv_num - 2 * omit_size; + int real_out_height = sub_output_height * sub_conv_num - 2 * omit_size; + int sub_filter_num = sub_conv_num * (arg->filter_num); + + int conv_output_size = + (align_to_x(sub_output_width * sub_filter_num, IMAGE_ALIGNMENT)) * + sub_output_height; + int ouput_size = conv_output_size * sub_conv_num; + + int align_sub_filter_num = align_to_x(sub_filter_num, FILTER_NUM_ALIGNMENT); + int align_sub_filter_count = + align_to_x(sub_filter_width * sub_filter_width * sub_channels, + FILTER_ELEMENT_ALIGNMENT); + int align_conv_sub_filter_count = + align_sub_filter_count * align_sub_filter_num; + + for (int i = 0; i < sub_conv_num; ++i) { + arg->conv_args[i].filter_num = (arg->sub_conv_num) * (arg->filter_num); + arg->conv_args[i].group_num = group_num; + + arg->conv_args[i].filter_scale_address = filter->scale; + arg->conv_args[i].relu_enabled = relu_enabled; + + arg->conv_args[i].kernel.width = sub_filter_width; + arg->conv_args[i].kernel.height = sub_filter_width; + arg->conv_args[i].kernel.stride_w = 1; + arg->conv_args[i].kernel.stride_h = 1; + + // DeconvParam.conv_args[i].image.address = (void*)ptr_image; + arg->conv_args[i].image.scale_address = input->scale; + arg->conv_args[i].image.channels = sub_channels; + arg->conv_args[i].image.width = (uint32_t)input->dims()[3]; + arg->conv_args[i].image.height = (uint32_t)input->dims()[2]; + arg->conv_args[i].image.pad_width = sub_pad; + arg->conv_args[i].image.pad_height = sub_pad; + arg->conv_args[i].image.address = input_ptr; + + arg->conv_args[i].sb_address = (void *)bs_ptr; + + char *filter_sub_space = + (char *)fpga_malloc(align_conv_sub_filter_count * sizeof(char)); + fpga_copy(filter_sub_space, + (char *)filter_ptr + i * align_conv_sub_filter_count, + align_conv_sub_filter_count); + arg->conv_args[i].filter_address = (void *)(filter_sub_space); + fpga_flush(filter_sub_space, align_conv_sub_filter_count); + + if (sub_conv_num == 1) { + arg->conv_args[i].output.address = out_ptr; + arg->conv_args[i].output.scale_address = out->scale; + } else { + half *ptr_output = (half *)fpga_malloc(conv_output_size * sizeof(half)); + arg->conv_args[i].output.address = (void *)((half *)ptr_output); + float *ptr_output_scale = (float *)fpga_malloc(2 * sizeof(float)); + arg->conv_args[i].output.scale_address = ptr_output_scale; + } + } + + arg->output.address = out_ptr; + arg->output.scale_address = out->scale; + // fpga_free(filter_ptr); +} } // namespace fpga } // namespace paddle_mobile diff --git a/src/fpga/V1/api.h b/src/fpga/V1/api.h index daa7902ab4a6cb72a77bba31f8cfe84c897f30a4..dbc3051b5784d3ecdf3cd08afb15242b7208a543 100644 --- a/src/fpga/V1/api.h +++ b/src/fpga/V1/api.h @@ -43,6 +43,25 @@ void fill_split_arg(struct SplitConvArgs* arg, framework::Tensor* input, framework::Tensor* out, framework::Tensor* filter, bool relu_enabled, int group_num, int stride_h, int stride_w, int padding_h, int padding_w, float* bs_ptr); +void fill_deconv_arg(struct DeconvArgs* arg, framework::Tensor* input, + framework::Tensor* out, framework::Tensor* filter, + bool relu_enabled, int group_num, int stride_h, + int stride_w, int padding_h, int padding_w, float* bs_ptr); + +void format_deconv_filter(framework::Tensor* filter_tensor, float max_value, + int group_num, int stride); + +template +void savefile(std::string filename, void* buffer, int dataSize, Dtype tmp) { + float data; + std::ofstream out(filename.c_str()); + for (int i = 0; i < dataSize; ++i) { + data = (((Dtype*)buffer)[i]); + out << data << std::endl; + } + out.close(); + return; +} } // namespace fpga } // namespace paddle_mobile diff --git a/src/fpga/V1/deconv_bias_scale.cpp b/src/fpga/V1/deconv_bias_scale.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0bcc91ddd295603d248639329773e74ef2e33a6a --- /dev/null +++ b/src/fpga/V1/deconv_bias_scale.cpp @@ -0,0 +1,48 @@ +/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +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. */ + +#include "fpga/V1/deconv_bias_scale.h" +// #include "deconv_bias_scale.h" +#include "fpga/V1/bias_scale.h" +// #include "bias_scale.h" +#include + +#include "fpga/V1/api.h" +// #include "fpga_api.h" +namespace paddle_mobile { +namespace fpga { +namespace deconv_bias_scale { + +void deconv_bias_scale_expand(float** bias_scale_array, int num, + int sub_conv_n) { + int sub_num = num * sub_conv_n; + float* ptr_tmp = *bias_scale_array; + float* ptr_bias_scale_expand = + (float*)fpga_malloc(sizeof(float) * sub_num * 2); + int scale_base_offset = sub_num; + for (int i = 0; i < sub_conv_n; ++i) { + int offset = num * i; + // copy bias + fpga_copy(ptr_bias_scale_expand + offset, ptr_tmp, num * sizeof(float)); + // copy scale + fpga_copy(ptr_bias_scale_expand + scale_base_offset + offset, ptr_tmp + num, + num * sizeof(float)); + } + *bias_scale_array = ptr_bias_scale_expand; + fpga_free(ptr_tmp); +} + +} // namespace deconv_bias_scale +} // namespace fpga +} // namespace paddle_mobile diff --git a/src/fpga/V1/deconv_bias_scale.h b/src/fpga/V1/deconv_bias_scale.h new file mode 100644 index 0000000000000000000000000000000000000000..7b9aaff756809b43884883b3333fcbc1dd2b6adf --- /dev/null +++ b/src/fpga/V1/deconv_bias_scale.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +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. */ + +#pragma once + +#define BS_NUM_ALIGNMENT 8 + +namespace paddle_mobile { +namespace fpga { +namespace deconv_bias_scale { + +void deconv_bias_scale_expand(float** bias_scale_array, int num, + int sub_conv_n); + +} // namespace deconv_bias_scale +} // namespace fpga +} // namespace paddle_mobile diff --git a/src/fpga/V1/deconv_filter.cpp b/src/fpga/V1/deconv_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..96634e520fd8638dd0ded1da7ca5b5ad33bd7aec --- /dev/null +++ b/src/fpga/V1/deconv_filter.cpp @@ -0,0 +1,277 @@ +/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +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. */ + +#include "fpga/V1/deconv_filter.h" +#include +#include +// #include "deconv_filter.h" +#include "fpga/V1/filter.h" +// #include "filter.h" +#include "fpga/V1/api.h" +// #include "fpga_api.h" + +// just for test +//#include +//#include "deconv.h" +//#include "deconv_api.h" +// using namespace std; +// using namespace paddle_mobile::fpga; +// using namespace baidu::fpga::deconv::api; +// namespace api = baidu::fpga::deconv::api; + +namespace paddle_mobile { +namespace fpga { +namespace deconv_filter { + +/* +inverse kernel weights of each channel for every filter +*/ +void deconv_inverse_filter(float** data_in, int num, int channel, int width, + int height) { + float* tmp = *data_in; + // float fix_range = 127;// float scale = fix_range / max; + int data_size = num * channel * width * height; + int hw_len = height * width; + float* tmp_data = (float*)fpga_malloc(data_size * sizeof(float)); + for (int i = 0; i < num; ++i) { + for (int j = 0; j < channel; ++j) { + for (int k = 0; k < hw_len; ++k) { + tmp_data[i * channel * hw_len + j * hw_len + k] = + (*data_in)[i * channel * hw_len + j * hw_len + hw_len - k - 1]; + } + } + } + *data_in = (float*)tmp_data; // + fpga_free(tmp); +} + +/* + calculate sub padding number +*/ +int deconv_calc_sub_pad(int filter_axis, int pad, int stride) { + if (stride == 0 || ((filter_axis - pad - 1) < 0)) { + // error + return 0; + } + return (filter_axis - pad - 1) / stride; +} +int deconv_get_sub_filter_axis(int filter_axis, int stride) { + return (filter_axis / stride); +} + +int deconv_get_sub_out_axis(int image_axis, int sub_pad, int sub_filter_axis) { + return ((image_axis + 2 * sub_pad - sub_filter_axis) + 1); +} + +/* + (filter_width-pad,filter_width-pad) is the first pixel of sub-pixel image + position. so the omit rows or columns is (stride - ) +*/ +int deconv_get_omit(int stride, int filter_width, int pad) { + if (((filter_width - pad) <= 0)) { // ((filter_width-pad) > stride) || + // error + return 0; + } + int idx = 1; + bool flag = false; + for (idx = 1; idx <= stride; ++idx) { + int j = idx; + for (; j <= filter_width;) { + if (j == filter_width - pad) { + flag = true; + break; + } + j = j + stride; + } + if (flag) { + break; + } + } + + return (stride - idx); +} + +int deconv_get_sub_filter_num(int filter_num, int stride) { + return filter_num * stride; +} + +void deconv_get_sub_filter(char** data_in, int height, int width, + int sub_conv_n, int kernel_num, int channel) { + char* ptr_tmp = *data_in; + int sub_num = kernel_num * sub_conv_n; + int sub_h = height / sub_conv_n; + int sub_w = width / sub_conv_n; + + int sub_filter_size = + kernel_num * sub_h * sub_w * channel * sub_conv_n * sub_conv_n; + + char* ptr_sub_filter = (char*)fpga_malloc(sub_filter_size * sizeof(char)); + for (int idx = 0; idx < sub_conv_n; ++idx) { + for (int nn = 0; nn < sub_num; ++nn) { + int ni = nn % kernel_num; + + int woff = sub_conv_n - 1 - (nn / kernel_num); // + + for (int hh = 0; hh < sub_h; ++hh) { + int hi = hh * sub_conv_n + idx % sub_conv_n; + for (int ww = 0; ww < sub_w; ++ww) { + int wi = ww * sub_conv_n + woff; // 1 0 + + int sidx = ((nn * sub_h + hh) * sub_w + ww) * channel; // + int kidx = ((ni * height + hi) * width + wi) * channel; // + + fpga_copy( + ptr_sub_filter + idx * sub_h * sub_w * channel * sub_num + sidx, + (*data_in) + kidx, channel * sizeof(char)); + // for (int cc =0; cc < channel; ++cc) { + // ptr_sub_filter[idx*sub_h*sub_w*channel*sub_num + sidx + cc] = + // (*data_in)[kidx + cc]; + // } + } + } + } + } + *data_in = ptr_sub_filter; + fpga_free(ptr_tmp); +} + +void deconv_NC_convert(float** filter_in, int kernel_num, int channels, + int hw) { + float* tmp = *filter_in; + float* ptr_filter = (float*)(paddle_mobile::fpga::fpga_malloc( + hw * kernel_num * channels * sizeof(float))); + + for (int c = 0; c < channels; ++c) { + for (int n = 0; n < kernel_num; ++n) { + paddle_mobile::fpga::fpga_copy(ptr_filter + n * hw + kernel_num * hw * c, + tmp + n * channels * hw + c * hw, + hw * sizeof(float)); + } + } + *filter_in = ptr_filter; + paddle_mobile::fpga::fpga_free(tmp); +} + +void deconv_format_filter(float** data_in, int num, int channel, int height, + int width, int group_num, float max, int stride) { + int data_size = channel * height * width * num; + + /*{ + float result2 = (float)0; + string filename = "origin_filter_data"; + api::savefile(filename, (void *)*data_in, data_size, result2); + }*/ + + deconv_inverse_filter(data_in, num, channel, width, height); + + /* { + float result2 = (float)0; + string filename = "inverse_filter_data"; + api::savefile(filename, (void *)*data_in, data_size, result2); + }*/ + + filter::quantize(data_in, data_size, max); + /* { + char result2 = (char)0; + string filename = "quantize_filter_data"; + api::savefile(filename, (void *)*data_in, data_size, result2); + }*/ + char** quantize_data = (char**)data_in; // NOLINT + + filter::convert_to_hwc(quantize_data, num, channel, height, width); + /*{ + char result2 = (char)0; + string filename = "convert_to_hwc_filter_data"; + api::savefile(filename, (void *)*quantize_data, data_size, + result2); + }*/ + + deconv_get_sub_filter(quantize_data, height, width, stride, num, channel); + /*{ + char result2 = (char)0; + string filename = "sub_filter_filter_data"; + api::savefile(filename, (void *)*quantize_data, data_size, result2); +}*/ + + int sub_conv_n = stride; + int sub_h = height / sub_conv_n; + int sub_w = width / sub_conv_n; + int sub_chw = sub_h * sub_w * channel; + int sub_num = sub_conv_n * num; + int division_capacity = filter::calc_division_capacity(sub_chw); + int num_per_div_before_alignment = + filter::calc_num_per_div(sub_num, group_num, division_capacity); + int num_per_div_after_alignment = + align_to_x(num_per_div_before_alignment, FILTER_NUM_ALIGNMENT); + int div_num = (sub_num + num_per_div_before_alignment - 1) / + num_per_div_before_alignment; + int residual = (sub_num) % num_per_div_before_alignment; + int num_after_alignment = num_per_div_after_alignment * + ((residual == 0) ? div_num : (div_num - 1)) + + align_to_x(residual, FILTER_NUM_ALIGNMENT); + + char** ptr_ptr_data = (char**)fpga_malloc(sub_conv_n * sizeof(char*)); + int origin_offset = sub_chw * sub_num; + for (int i = 0; i < sub_conv_n; ++i) { + (ptr_ptr_data)[i] = (char*)fpga_malloc(origin_offset * sizeof(char)); + fpga_copy((ptr_ptr_data)[i], (*quantize_data) + origin_offset * i, + origin_offset * sizeof(char)); + + /* char result2 = (char)0; + string filename = "ptr_ptr_data" + to_string(i); + api::savefile(filename, (void *)(ptr_ptr_data[i]), origin_offset, + result2); + */ + } + // char result2 = (char)0; + // string filename = "interleave"; + // api::savefile(filename, (void *)*ptr_ptr_data, origin_offset, + // result2); + fpga_free(*quantize_data); + + int align_offset = + align_to_x(sub_chw, FILTER_ELEMENT_ALIGNMENT) * num_after_alignment; + char* ptr_space = (char*)fpga_malloc(sub_conv_n * align_offset * + sizeof(char)); // continuous space + for (int i = 0; i < sub_conv_n; ++i) { + int offset = i * origin_offset; + char* ptr_tmp = (ptr_ptr_data)[i]; + + filter::align_element(&ptr_tmp, sub_num, sub_chw); + filter::align_num(&ptr_tmp, num_per_div_before_alignment, sub_num, sub_chw); + + filter::reorder(&ptr_tmp, num_after_alignment, sub_chw); + filter::interleave(&ptr_tmp, num_after_alignment, sub_chw); + + /* char result2 = (char)0; + string filename = "interleave" + to_string(i); + api::savefile(filename, (void *)ptr_tmp, align_offset, result2); +*/ + fpga_copy(ptr_space + i * align_offset, ptr_tmp, align_offset); + fpga_free(ptr_tmp); + } + *data_in = (float*)ptr_space; + + /* { + char result2 = (char)0; + string filename = "ptr_space"; + api::savefile(filename, (void *)ptr_space, sub_conv_n * + align_offset, result2); + }*/ + fpga_flush(ptr_space, sub_conv_n * align_offset * sizeof(char)); +} + +} // namespace deconv_filter +} // namespace fpga +} // namespace paddle_mobile diff --git a/src/fpga/V1/deconv_filter.h b/src/fpga/V1/deconv_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..e89ebe5087a3ab8ee7ef007696e5b1fd50d4173e --- /dev/null +++ b/src/fpga/V1/deconv_filter.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +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. */ + +#pragma once + +namespace paddle_mobile { +namespace fpga { +namespace deconv_filter { + +void deconv_inverse_filter(float** data_in, int num, int channel, int width, + int height); +int deconv_calc_sub_pad(int filter_axis, int pad, int stride); +int deconv_get_sub_filter_num(int filter_num, int stride); +int deconv_get_sub_filter_axis(int filter_axis, int stride); +int deconv_get_sub_out_axis(int image_axis, int sub_pad, int sub_filter_axis); +int deconv_get_omit(int stride, int filter_width, int pad); +void deconv_get_sub_filter(char** data_in, int height, int width, + int sub_conv_n, int kernel_num, int channel); +void deconv_format_filter(float** data_in, int num, int channel, int height, + int width, int group_num, float max, int stride); +void deconv_NC_convert(float** filter_in, int kernel_num, int channels, int hw); + +} // namespace deconv_filter +} // namespace fpga +} // namespace paddle_mobile diff --git a/src/fpga/V1/filter.cpp b/src/fpga/V1/filter.cpp index d67c9fdc18ac8f715a5389625b6d76b71281e349..1f204ca30289136fc3ff83e2712ff32842a88100 100644 --- a/src/fpga/V1/filter.cpp +++ b/src/fpga/V1/filter.cpp @@ -146,12 +146,16 @@ void align_num(char **data_in, int num_per_div_before_alignment, int num, memset(data_tmp, 0, num_element * sizeof(char)); - for (i = 0; i < div_num; i++) { + for (i = 0; i < div_num - 1; i++) { memcpy(data_tmp + num_per_div_after_alignment * align_chw * i, *data_in + num_per_div_before_alignment * align_chw * i, num_per_div_before_alignment * align_chw); } + memcpy(data_tmp + num_per_div_after_alignment * align_chw * i, + *data_in + num_per_div_before_alignment * align_chw * i, + (num - (div_num - 1) * num_per_div_before_alignment) * align_chw); + *data_in = data_tmp; fpga_free(tmp); } diff --git a/src/fpga/V1/filter.h b/src/fpga/V1/filter.h index 5d03ee9b4a0b1455b27f7c978678bd1dfaa5a698..7bcc334738be98a49fc7eb25cf7090c0f8b6b3b3 100644 --- a/src/fpga/V1/filter.h +++ b/src/fpga/V1/filter.h @@ -29,11 +29,11 @@ void convert_to_hwc(char** data_in, int num, int channel, int height, int width); float find_max(float* data_in, int data_size); void quantize(float** data_in, int data_size, float max); -void align_element(float** data_in, int num, int chw); +void align_element(char** data_in, int num, int chw); void align_num(char** data_in, int num_per_div_before_alignment, int num, int chw); -void reorder(float** data_in, int num_after_alignment, int chw); -void interleave(float** data_in, int num_after_alignment, int chw); +void reorder(char** data_in, int num_after_alignment, int chw); +void interleave(char** data_in, int num_after_alignment, int chw); void format_filter(float** data_in, int num, int channel, int height, int width, int group_num, float max); diff --git a/src/operators/kernel/fpga/V1/deconv_add_kernel.cpp b/src/operators/kernel/fpga/V1/deconv_add_kernel.cpp index 39d7e818976b56eaea8649392784e7b5dc8b7e1f..7ab25193c86228ba290bc4a79fd1fa203a8e3617 100644 --- a/src/operators/kernel/fpga/V1/deconv_add_kernel.cpp +++ b/src/operators/kernel/fpga/V1/deconv_add_kernel.cpp @@ -23,12 +23,61 @@ namespace operators { template <> bool DeconvAddKernel::Init(FusionDeconvAddParam *param) { + bool relu_enabled = false; + auto input = const_cast(param->Input()); + const Tensor *bias = param->Bias(); + auto bias_ptr = bias->data(); + auto filter = const_cast(param->Filter()); + auto out = param->Output(); + + PADDLE_MOBILE_ENFORCE(out->dims()[1] == bias->dims()[0], + "Output channel should be equal to bias number"); + int channel = out->dims()[1]; + + int sub_conv_n = param->Strides()[0]; + auto bs_ptr = (float *)fpga::fpga_malloc(2 * channel * sub_conv_n * + sizeof(float)); // NOLINT + + for (int i = 0; i < channel * sub_conv_n; i++) { + bs_ptr[i + sub_conv_n * channel] = 1; + bs_ptr[i] = bias_ptr[i % (channel)]; + } + + PADDLE_MOBILE_ENFORCE(param->Strides()[1] == param->Strides()[0], + "stride_width should be equal to stride_height "); + PADDLE_MOBILE_ENFORCE(filter->dims()[2] == filter->dims()[3], + "filter width should be equal to filter height "); + PADDLE_MOBILE_ENFORCE(((filter->dims()[2] % param->Strides()[0]) == 0), + "filter axis should be the multiple of stride axis "); + + float max_value = fpga::filter_find_max(filter); + fpga::format_deconv_filter(filter, max_value, param->Groups(), + param->Strides()[0]); + + // int element_num_per_div = + // fpga::get_filter_num_per_div(filter, param->Groups()); + + // deconv only support group=1 && no spilt + fpga::format_bias_scale_array(&bs_ptr, channel * sub_conv_n, + channel * sub_conv_n); + + fpga::format_fp16_ofm(out); + + fpga::DeconvArgs deconv_arg = {0}; + fpga::fill_deconv_arg(&deconv_arg, input, out, filter, relu_enabled, + param->Groups(), param->Strides()[0], + param->Strides()[1], param->Paddings()[0], + param->Paddings()[1], bs_ptr); + param->SetFpgaArgs(deconv_arg); + return true; } template <> void DeconvAddKernel::Compute( - const FusionDeconvAddParam ¶m) {} + const FusionDeconvAddParam ¶m) { + fpga::ComputeFpgaDeconv(param.FpgaArgs()); +} } // namespace operators } // namespace paddle_mobile diff --git a/src/operators/kernel/fpga/V1/deconv_add_relu_kernel.cpp b/src/operators/kernel/fpga/V1/deconv_add_relu_kernel.cpp index ef2556208a8650a86522264f40f42cb596ec4190..a9a6909b00b7608d5edb26aa943c1c9cae663b3e 100644 --- a/src/operators/kernel/fpga/V1/deconv_add_relu_kernel.cpp +++ b/src/operators/kernel/fpga/V1/deconv_add_relu_kernel.cpp @@ -24,12 +24,60 @@ namespace operators { template <> bool DeconvAddReluKernel::Init( FusionDeconvAddReluParam *param) { + bool relu_enabled = true; + auto input = const_cast(param->Input()); + const Tensor *bias = param->Bias(); + auto bias_ptr = bias->data(); + auto filter = const_cast(param->Filter()); + auto out = param->Output(); + + PADDLE_MOBILE_ENFORCE(out->dims()[1] == bias->dims()[0], + "Output channel should be equal to bias number"); + int channel = out->dims()[1]; + + int sub_conv_n = param->Strides()[0]; + auto bs_ptr = (float *)fpga::fpga_malloc(2 * channel * sub_conv_n * + sizeof(float)); // NOLINT + + for (int i = 0; i < channel * sub_conv_n; i++) { + bs_ptr[i + sub_conv_n * channel] = 1; + bs_ptr[i] = bias_ptr[i % (channel)]; + } + + PADDLE_MOBILE_ENFORCE(param->Strides()[1] == param->Strides()[0], + "stride_width should be equal to stride_height "); + PADDLE_MOBILE_ENFORCE(filter->dims()[2] == filter->dims()[3], + "filter width should be equal to filter height "); + PADDLE_MOBILE_ENFORCE(((filter->dims()[2] % param->Strides()[0]) == 0), + "filter axis should be the multiple of stride axis "); + + float max_value = fpga::filter_find_max(filter); + fpga::format_deconv_filter(filter, max_value, param->Groups(), + param->Strides()[0]); + + // int element_num_per_div = + // fpga::get_filter_num_per_div(filter, param->Groups()); + + // deconv only support group=1 && no spilt + fpga::format_bias_scale_array(&bs_ptr, channel * sub_conv_n, + channel * sub_conv_n); + + fpga::format_fp16_ofm(out); + + fpga::DeconvArgs deconv_arg = {0}; + fpga::fill_deconv_arg(&deconv_arg, input, out, filter, relu_enabled, + param->Groups(), param->Strides()[0], + param->Strides()[1], param->Paddings()[0], + param->Paddings()[1], bs_ptr); + param->SetFpgaArgs(deconv_arg); return true; } template <> void DeconvAddReluKernel::Compute( - const FusionDeconvAddReluParam ¶m) {} + const FusionDeconvAddReluParam ¶m) { + fpga::ComputeFpgaDeconv(param.FpgaArgs()); +} } // namespace operators } // namespace paddle_mobile