|
|
|
@ -14,7 +14,9 @@ limitations under the License. */
|
|
|
|
|
|
|
|
|
|
#include "paddle/fluid/operators/math/im2col.h"
|
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include "paddle/fluid/operators/math/im2col_cfo_cpu.h"
|
|
|
|
|
|
|
|
|
|
template <typename DeviceContext, typename Place>
|
|
|
|
|
void testIm2col() {
|
|
|
|
@ -160,82 +162,111 @@ void testIm2col() {
|
|
|
|
|
delete context;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void testIm2colCPU(int ic, int ih, int iw, int fh, int fw, int ph, int pw) {
|
|
|
|
|
paddle::framework::Tensor input;
|
|
|
|
|
paddle::framework::Tensor output;
|
|
|
|
|
paddle::framework::Tensor ref_output;
|
|
|
|
|
std::vector<int> padding({ph, pw});
|
|
|
|
|
std::vector<int> stride({1, 1}); // stride_y, stride_x
|
|
|
|
|
std::vector<int> dilation({1, 1}); // dilation_y, dilation_x
|
|
|
|
|
int output_height = (ih - fh + padding[0] * 2) / stride[0] + 1;
|
|
|
|
|
int output_width = (iw - fw + padding[1] * 2) / stride[1] + 1;
|
|
|
|
|
float* input_ptr =
|
|
|
|
|
input.mutable_data<float>({ic, ih, iw}, paddle::platform::CPUPlace());
|
|
|
|
|
for (int i = 0; i < input.numel(); ++i) {
|
|
|
|
|
input_ptr[i] = static_cast<float>(i + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
paddle::platform::CPUPlace place;
|
|
|
|
|
paddle::platform::CPUDeviceContext context(place);
|
|
|
|
|
output.mutable_data<float>({ic, fh, fw, output_height, output_width}, place);
|
|
|
|
|
ref_output.mutable_data<float>({ic, fh, fw, output_height, output_width},
|
|
|
|
|
place);
|
|
|
|
|
paddle::operators::math::Im2ColFunctor<
|
|
|
|
|
paddle::operators::math::ColFormat::kCFO,
|
|
|
|
|
paddle::platform::CPUDeviceContext, float>
|
|
|
|
|
im2col;
|
|
|
|
|
im2col(context, input, dilation, stride, padding, &output);
|
|
|
|
|
auto ref_im2col = [&](
|
|
|
|
|
const paddle::framework::Tensor& im, const std::vector<int>& dilation,
|
|
|
|
|
const std::vector<int>& stride, const std::vector<int>& padding,
|
|
|
|
|
paddle::framework::Tensor* col) {
|
|
|
|
|
int im_channels = im.dims()[0];
|
|
|
|
|
int im_height = im.dims()[1];
|
|
|
|
|
int im_width = im.dims()[2];
|
|
|
|
|
int filter_height = col->dims()[1];
|
|
|
|
|
int filter_width = col->dims()[2];
|
|
|
|
|
int output_height = col->dims()[3];
|
|
|
|
|
int output_width = col->dims()[4];
|
|
|
|
|
int channels_col = im_channels * filter_height * filter_width;
|
|
|
|
|
|
|
|
|
|
const float* im_data = im.data<float>();
|
|
|
|
|
float* col_data = col->data<float>();
|
|
|
|
|
for (int c = 0; c < channels_col; ++c) {
|
|
|
|
|
int w_offset = c % filter_width;
|
|
|
|
|
int h_offset = (c / filter_width) % filter_height;
|
|
|
|
|
int c_im = c / (filter_width * filter_height);
|
|
|
|
|
for (int h = 0; h < output_height; ++h) {
|
|
|
|
|
int im_row_idx = h * stride[0] - padding[0] + h_offset * dilation[0];
|
|
|
|
|
for (int w = 0; w < output_width; ++w) {
|
|
|
|
|
int im_col_idx = w * stride[1] - padding[1] + w_offset * dilation[1];
|
|
|
|
|
int col_idx = (c * output_height + h) * output_width + w;
|
|
|
|
|
int im_idx = (im_row_idx + c_im * im_height) * im_width + im_col_idx;
|
|
|
|
|
col_data[col_idx] = (im_row_idx < 0 || im_row_idx >= im_height ||
|
|
|
|
|
im_col_idx < 0 || im_col_idx >= im_width)
|
|
|
|
|
? 0.f
|
|
|
|
|
: im_data[im_idx];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ref_im2col(input, dilation, stride, padding, &ref_output);
|
|
|
|
|
|
|
|
|
|
float* out_cfo_ptr = output.data<float>();
|
|
|
|
|
float* out_ref_ptr = ref_output.data<float>();
|
|
|
|
|
for (int i = 0; i < output.numel(); ++i) {
|
|
|
|
|
EXPECT_EQ(out_cfo_ptr[i], out_ref_ptr[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(math, im2col) {
|
|
|
|
|
testIm2col<paddle::platform::CPUDeviceContext, paddle::platform::CPUPlace>();
|
|
|
|
|
testIm2colCPU(/*ic*/ 3, /*ih*/ 5, /*iw*/ 5, /*fh*/ 3, /*fw*/ 2, /*ph*/ 0,
|
|
|
|
|
/*pw*/ 0);
|
|
|
|
|
testIm2colCPU(/*ic*/ 2, /*ih*/ 5, /*iw*/ 4, /*fh*/ 3, /*fw*/ 3, /*ph*/ 1,
|
|
|
|
|
/*pw*/ 1);
|
|
|
|
|
#ifdef PADDLE_WITH_CUDA
|
|
|
|
|
testIm2col<paddle::platform::CUDADeviceContext,
|
|
|
|
|
paddle::platform::CUDAPlace>();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define PREPARE_IM2COL_CPU \
|
|
|
|
|
paddle::platform::CPUPlace place; \
|
|
|
|
|
paddle::platform::CPUDeviceContext context(place); \
|
|
|
|
|
paddle::framework::Tensor input; \
|
|
|
|
|
paddle::framework::Tensor out; \
|
|
|
|
|
paddle::framework::Tensor ref; \
|
|
|
|
|
std::vector<int> padding({ph, pw}); \
|
|
|
|
|
std::vector<int> stride({1, 1}); \
|
|
|
|
|
std::vector<int> dilation({1, 1}); \
|
|
|
|
|
float* input_ptr = input.mutable_data<float>({ic, ih, iw}, place); \
|
|
|
|
|
for (int i = 0; i < input.numel(); ++i) { \
|
|
|
|
|
input_ptr[i] = static_cast<float>(i + 1); \
|
|
|
|
|
} \
|
|
|
|
|
int output_height = (ih - fh + padding[0] * 2) / stride[0] + 1; \
|
|
|
|
|
int output_width = (iw - fw + padding[1] * 2) / stride[1] + 1; \
|
|
|
|
|
out.mutable_data<float>({ic, fh, fw, output_height, output_width}, place); \
|
|
|
|
|
ref.mutable_data<float>({ic, fh, fw, output_height, output_width}, place); \
|
|
|
|
|
paddle::operators::math::Im2ColFunctor< \
|
|
|
|
|
paddle::operators::math::ColFormat::kCFO, \
|
|
|
|
|
paddle::platform::CPUDeviceContext, float> \
|
|
|
|
|
im2col
|
|
|
|
|
|
|
|
|
|
void testIm2colCPU(int ic, int ih, int iw, int fh, int fw, int ph, int pw) {
|
|
|
|
|
PREPARE_IM2COL_CPU;
|
|
|
|
|
|
|
|
|
|
im2col(context, input, dilation, stride, padding, &out);
|
|
|
|
|
paddle::operators::math::im2col_common<float>(input, dilation, stride,
|
|
|
|
|
padding, &ref);
|
|
|
|
|
|
|
|
|
|
float* ref_data = ref.data<float>();
|
|
|
|
|
float* out_data = out.data<float>();
|
|
|
|
|
for (int i = 0; i < out.numel(); ++i) {
|
|
|
|
|
EXPECT_EQ(out_data[i], ref_data[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void benchIm2col(int ic, int ih, int iw, int fh, int fw, int ph, int pw) {
|
|
|
|
|
PREPARE_IM2COL_CPU;
|
|
|
|
|
constexpr int repeat = 100;
|
|
|
|
|
auto GetCurrentMs = []() -> double {
|
|
|
|
|
struct timeval time;
|
|
|
|
|
gettimeofday(&time, NULL);
|
|
|
|
|
return 1e+3 * time.tv_sec + 1e-3 * time.tv_usec;
|
|
|
|
|
};
|
|
|
|
|
auto t1 = GetCurrentMs();
|
|
|
|
|
for (int i = 0; i < repeat; ++i) {
|
|
|
|
|
im2col(context, input, dilation, stride, padding, &out);
|
|
|
|
|
}
|
|
|
|
|
auto t2 = GetCurrentMs();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < repeat; ++i) {
|
|
|
|
|
paddle::operators::math::im2col_common<float>(input, dilation, stride,
|
|
|
|
|
padding, &ref);
|
|
|
|
|
}
|
|
|
|
|
auto t3 = GetCurrentMs();
|
|
|
|
|
|
|
|
|
|
LOG(INFO) << "before: " << (t3 - t2) / repeat
|
|
|
|
|
<< ",after: " << (t2 - t1) / repeat
|
|
|
|
|
<< ",boost: " << ((t3 - t2) / (t2 - t1) - 1) * 100 << "%";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(math, im2col_cputest) {
|
|
|
|
|
// padding_h == padding_w
|
|
|
|
|
for (int p = 0; p < 4; ++p) {
|
|
|
|
|
// width == height
|
|
|
|
|
testIm2colCPU(/*ic*/ 2, /*ih*/ 5, /*iw*/ 5, /*fh*/ 4, /*fw*/ 4, /*ph*/ p,
|
|
|
|
|
/*pw*/ p);
|
|
|
|
|
testIm2colCPU(/*ic*/ 2, /*ih*/ 4, /*iw*/ 4, /*fh*/ 3, /*fw*/ 3, /*ph*/ p,
|
|
|
|
|
/*pw*/ p);
|
|
|
|
|
testIm2colCPU(/*ic*/ 2, /*ih*/ 4, /*iw*/ 4, /*fh*/ 2, /*fw*/ 2, /*ph*/ p,
|
|
|
|
|
/*pw*/ p);
|
|
|
|
|
|
|
|
|
|
// height != width
|
|
|
|
|
testIm2colCPU(/*ic*/ 2, /*ih*/ 5, /*iw*/ 4, /*fh*/ 2, /*fw*/ 3, /*ph*/ p,
|
|
|
|
|
/*pw*/ p);
|
|
|
|
|
testIm2colCPU(/*ic*/ 2, /*ih*/ 5, /*iw*/ 4, /*fh*/ 1, /*fw*/ 3, /*ph*/ p,
|
|
|
|
|
/*pw*/ p);
|
|
|
|
|
testIm2colCPU(/*ic*/ 2, /*ih*/ 4, /*iw*/ 5, /*fh*/ 3, /*fw*/ 1, /*ph*/ p,
|
|
|
|
|
/*pw*/ p);
|
|
|
|
|
|
|
|
|
|
// filter == 1
|
|
|
|
|
testIm2colCPU(/*ic*/ 3, /*ih*/ 4, /*iw*/ 4, /*fh*/ 1, /*fw*/ 1, /*ph*/ p,
|
|
|
|
|
/*pw*/ p);
|
|
|
|
|
testIm2colCPU(/*ic*/ 3, /*ih*/ 3, /*iw*/ 4, /*fh*/ 1, /*fw*/ 1, /*ph*/ p,
|
|
|
|
|
/*pw*/ p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// padding_h != padding_w
|
|
|
|
|
testIm2colCPU(/*ic*/ 2, /*ih*/ 4, /*iw*/ 4, /*fh*/ 2, /*fw*/ 3, /*ph*/ 1,
|
|
|
|
|
/*pw*/ 2);
|
|
|
|
|
|
|
|
|
|
// benchmark
|
|
|
|
|
for (int p : {0, 1}) {
|
|
|
|
|
for (int k : {1, 3, 5}) {
|
|
|
|
|
LOG(INFO) << "padding == " << p << ", filter == " << k;
|
|
|
|
|
benchIm2col(/*ic*/ 3, /*ih*/ 224, /*iw*/ 224, /*fh*/ k, /*fw*/ k,
|
|
|
|
|
/*ph*/ p, /*pw*/ p);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|