chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
cc_test(
|
||||
selected_rows_functor_test
|
||||
SRCS selected_rows_functor_test.cc
|
||||
DEPS phi common)
|
||||
cc_test(
|
||||
im2col_test
|
||||
SRCS im2col_test.cc
|
||||
DEPS phi common)
|
||||
cc_test(
|
||||
vol2col_test
|
||||
SRCS vol2col_test.cc
|
||||
DEPS phi common)
|
||||
cc_test(
|
||||
beam_search_test
|
||||
SRCS beam_search_test.cc
|
||||
DEPS phi common)
|
||||
if(WITH_GPU)
|
||||
nv_test(
|
||||
selected_rows_functor_gpu_test
|
||||
SRCS selected_rows_functor_test.cu.cc
|
||||
DEPS phi common)
|
||||
endif()
|
||||
if(WITH_ROCM)
|
||||
hip_test(
|
||||
selected_rows_functor_gpu_test
|
||||
SRCS selected_rows_functor_test.cu.cc
|
||||
DEPS phi common)
|
||||
endif()
|
||||
cc_test(
|
||||
concat_test
|
||||
SRCS concat_test.cc
|
||||
DEPS phi common)
|
||||
|
||||
if(WITH_TESTING AND TEST im2col_test)
|
||||
set_tests_properties(im2col_test PROPERTIES TIMEOUT 120)
|
||||
endif()
|
||||
@@ -0,0 +1,245 @@
|
||||
/* Copyright (c) 2016 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 "paddle/phi/kernels/funcs/math/beam_search.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "paddle/fluid/framework/operator.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
#include "paddle/phi/core/platform/device_context.h"
|
||||
|
||||
void PrepareCPUTensors(phi::DenseTensor* ids,
|
||||
phi::DenseTensor* scores,
|
||||
phi::DenseTensor* pre_ids,
|
||||
phi::DenseTensor* pre_scores) {
|
||||
// lod
|
||||
phi::LegacyLoD lod;
|
||||
std::vector<size_t> level0({0, 2, 4});
|
||||
std::vector<size_t> level1({0, 1, 2, 3, 4});
|
||||
lod.push_back(level0);
|
||||
lod.push_back(level1);
|
||||
ids->set_lod(lod);
|
||||
scores->set_lod(lod);
|
||||
|
||||
auto dims = common::make_ddim({4, 3});
|
||||
ids->Resize(dims);
|
||||
scores->Resize(dims);
|
||||
|
||||
phi::CPUPlace place;
|
||||
auto* ids_data = ids->mutable_data<int64_t>(place);
|
||||
auto* scores_data = scores->mutable_data<float>(place);
|
||||
std::vector<int64_t> ids_vec_data({4, 2, 5, 2, 1, 3, 3, 5, 2, 8, 2, 1});
|
||||
std::vector<float> scores_vec_data(
|
||||
{0.6f, 0.3f, 0.5f, 0.2f, 0.3f, 0.1f, 0.9f, 0.5f, 0.1f, 0.7f, 0.5f, 0.1f});
|
||||
|
||||
PADDLE_ENFORCE_EQ(
|
||||
static_cast<size_t>(ids->numel()),
|
||||
ids_vec_data.size(),
|
||||
common::errors::InvalidArgument(
|
||||
"Required ids->numel() should be equal to ids_vec_data.size(). "));
|
||||
PADDLE_ENFORCE_EQ(
|
||||
static_cast<size_t>(ids->numel()),
|
||||
scores_vec_data.size(),
|
||||
common::errors::InvalidArgument(
|
||||
"Required ids->numel() should be equal to scores_vec_data.size(). "));
|
||||
|
||||
for (int i = 0; i < ids->numel(); i++) {
|
||||
ids_data[i] = ids_vec_data[i];
|
||||
scores_data[i] = scores_vec_data[i];
|
||||
}
|
||||
|
||||
// pre_ids
|
||||
pre_ids->Resize(common::make_ddim({4, 1}));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
pre_ids->mutable_data<int64_t>(place)[i] = i + 1;
|
||||
}
|
||||
|
||||
// pre_scores
|
||||
pre_scores->Resize(common::make_ddim({4, 1}));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
pre_scores->mutable_data<float>(place)[i] = 0.1 * (i + 1); // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DeviceContext, typename Place>
|
||||
void TestBeamSearch() {
|
||||
phi::DenseTensor ids;
|
||||
phi::DenseTensor scores;
|
||||
phi::DenseTensor pre_ids;
|
||||
phi::DenseTensor pre_scores;
|
||||
|
||||
auto* place = new Place();
|
||||
DeviceContext* context = new DeviceContext(*place);
|
||||
context->SetAllocator(paddle::memory::allocation::AllocatorFacade::Instance()
|
||||
.GetAllocator(phi::CPUPlace())
|
||||
.get());
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
PrepareCPUTensors(&ids, &scores, &pre_ids, &pre_scores);
|
||||
} else {
|
||||
phi::DenseTensor cpu_ids;
|
||||
phi::DenseTensor cpu_scores;
|
||||
phi::DenseTensor cpu_pre_ids;
|
||||
phi::DenseTensor cpu_pre_scores;
|
||||
|
||||
PrepareCPUTensors(&cpu_ids, &cpu_scores, &cpu_pre_ids, &cpu_pre_scores);
|
||||
|
||||
paddle::framework::TensorCopySync(cpu_ids, *place, &ids);
|
||||
paddle::framework::TensorCopySync(cpu_scores, *place, &scores);
|
||||
paddle::framework::TensorCopySync(cpu_pre_ids, *place, &pre_ids);
|
||||
paddle::framework::TensorCopySync(cpu_pre_scores, *place, &pre_scores);
|
||||
|
||||
ids.set_lod(cpu_ids.lod());
|
||||
scores.set_lod(cpu_scores.lod());
|
||||
pre_ids.set_lod(cpu_pre_ids.lod());
|
||||
pre_scores.set_lod(cpu_pre_scores.lod());
|
||||
}
|
||||
|
||||
phi::DenseTensor selected_ids;
|
||||
phi::DenseTensor selected_scores;
|
||||
phi::DenseTensor parent_idx;
|
||||
|
||||
size_t level = 0;
|
||||
size_t beam_size = 2;
|
||||
int end_id = 0;
|
||||
phi::math::BeamSearchFunctor<DeviceContext, float> beamsearch;
|
||||
beamsearch(*context,
|
||||
&pre_ids,
|
||||
&pre_scores,
|
||||
&ids,
|
||||
&scores,
|
||||
&selected_ids,
|
||||
&selected_scores,
|
||||
&parent_idx,
|
||||
level,
|
||||
beam_size,
|
||||
end_id,
|
||||
true);
|
||||
|
||||
ASSERT_EQ(selected_ids.lod(), selected_scores.lod());
|
||||
|
||||
phi::DenseTensor cpu_selected_ids;
|
||||
phi::DenseTensor cpu_selected_scores;
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
cpu_selected_ids = selected_ids;
|
||||
cpu_selected_scores = selected_scores;
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(
|
||||
selected_ids, phi::CPUPlace(), &cpu_selected_ids);
|
||||
paddle::framework::TensorCopySync(
|
||||
selected_scores, phi::CPUPlace(), &cpu_selected_scores);
|
||||
cpu_selected_ids.set_lod(selected_ids.lod());
|
||||
cpu_selected_scores.set_lod(selected_scores.lod());
|
||||
}
|
||||
|
||||
std::vector<int64_t> expected_ids({4, 5, 3, 8});
|
||||
std::vector<float> expected_scores({0.6f, 0.5f, 0.9f, 0.7f});
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ASSERT_EQ(expected_ids[i], cpu_selected_ids.data<int64_t>()[i]);
|
||||
ASSERT_EQ(expected_scores[i], cpu_selected_scores.data<float>()[i]);
|
||||
}
|
||||
|
||||
delete place;
|
||||
delete context;
|
||||
}
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
template <>
|
||||
void TestBeamSearch<phi::GPUContext, phi::GPUPlace>() {
|
||||
phi::DenseTensor ids;
|
||||
phi::DenseTensor scores;
|
||||
phi::DenseTensor pre_ids;
|
||||
phi::DenseTensor pre_scores;
|
||||
|
||||
auto* place = new phi::GPUPlace();
|
||||
auto* context = new phi::GPUContext(*place);
|
||||
context->SetAllocator(paddle::memory::allocation::AllocatorFacade::Instance()
|
||||
.GetAllocator(*place, context->stream())
|
||||
.get());
|
||||
context->PartialInitWithAllocator();
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
PrepareCPUTensors(&ids, &scores, &pre_ids, &pre_scores);
|
||||
} else {
|
||||
phi::DenseTensor cpu_ids;
|
||||
phi::DenseTensor cpu_scores;
|
||||
phi::DenseTensor cpu_pre_ids;
|
||||
phi::DenseTensor cpu_pre_scores;
|
||||
|
||||
PrepareCPUTensors(&cpu_ids, &cpu_scores, &cpu_pre_ids, &cpu_pre_scores);
|
||||
|
||||
paddle::framework::TensorCopySync(cpu_ids, *place, &ids);
|
||||
paddle::framework::TensorCopySync(cpu_scores, *place, &scores);
|
||||
paddle::framework::TensorCopySync(cpu_pre_ids, *place, &pre_ids);
|
||||
paddle::framework::TensorCopySync(cpu_pre_scores, *place, &pre_scores);
|
||||
|
||||
ids.set_lod(cpu_ids.lod());
|
||||
scores.set_lod(cpu_scores.lod());
|
||||
pre_ids.set_lod(cpu_pre_ids.lod());
|
||||
pre_scores.set_lod(cpu_pre_scores.lod());
|
||||
}
|
||||
|
||||
phi::DenseTensor selected_ids;
|
||||
phi::DenseTensor selected_scores;
|
||||
phi::DenseTensor parent_idx;
|
||||
|
||||
size_t level = 0;
|
||||
size_t beam_size = 2;
|
||||
int end_id = 0;
|
||||
phi::math::BeamSearchFunctor<phi::GPUContext, float> beamsearch;
|
||||
beamsearch(*context,
|
||||
&pre_ids,
|
||||
&pre_scores,
|
||||
&ids,
|
||||
&scores,
|
||||
&selected_ids,
|
||||
&selected_scores,
|
||||
&parent_idx,
|
||||
level,
|
||||
beam_size,
|
||||
end_id,
|
||||
true);
|
||||
|
||||
ASSERT_EQ(selected_ids.lod(), selected_scores.lod());
|
||||
|
||||
phi::DenseTensor cpu_selected_ids;
|
||||
phi::DenseTensor cpu_selected_scores;
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
cpu_selected_ids = selected_ids;
|
||||
cpu_selected_scores = selected_scores;
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(
|
||||
selected_ids, phi::CPUPlace(), &cpu_selected_ids);
|
||||
paddle::framework::TensorCopySync(
|
||||
selected_scores, phi::CPUPlace(), &cpu_selected_scores);
|
||||
cpu_selected_ids.set_lod(selected_ids.lod());
|
||||
cpu_selected_scores.set_lod(selected_scores.lod());
|
||||
}
|
||||
|
||||
std::vector<int64_t> expected_ids({4, 5, 3, 8});
|
||||
std::vector<float> expected_scores({0.6f, 0.5f, 0.9f, 0.7f});
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ASSERT_EQ(expected_ids[i], cpu_selected_ids.data<int64_t>()[i]);
|
||||
ASSERT_EQ(expected_scores[i], cpu_selected_scores.data<float>()[i]);
|
||||
}
|
||||
|
||||
delete place;
|
||||
delete context;
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(BeamSearch, CPU) { TestBeamSearch<phi::CPUContext, phi::CPUPlace>(); }
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
TEST(BeamSearch, GPU) { TestBeamSearch<phi::GPUContext, phi::GPUPlace>(); }
|
||||
#endif
|
||||
@@ -0,0 +1,489 @@
|
||||
/* 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 <gtest/gtest.h>
|
||||
|
||||
#include "paddle/fluid/framework/tensor_util.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
#include "paddle/phi/core/platform/device_context.h"
|
||||
#include "paddle/phi/kernels/funcs/concat_and_split_functor.h"
|
||||
|
||||
/**
|
||||
* case 1:
|
||||
* inputs:
|
||||
* t_a.shape: [2, 3, 4]
|
||||
* t_b.shape: [3, 3, 4]
|
||||
* output:
|
||||
* out.shape: [5, 3, 4]
|
||||
*/
|
||||
template <typename DeviceContext, typename Place>
|
||||
void ConcatCase1(DeviceContext* context) {
|
||||
phi::DenseTensor input_a_cpu;
|
||||
phi::DenseTensor input_b_cpu;
|
||||
phi::DenseTensor out_cpu;
|
||||
|
||||
phi::DenseTensor input_a;
|
||||
phi::DenseTensor input_b;
|
||||
phi::DenseTensor out;
|
||||
|
||||
auto dim_a = common::make_ddim({2, 3, 4});
|
||||
auto dim_b = common::make_ddim({3, 3, 4});
|
||||
auto dim_out = common::make_ddim({5, 3, 4});
|
||||
|
||||
input_a.mutable_data<int>(dim_a, Place());
|
||||
input_b.mutable_data<int>(dim_b, Place());
|
||||
out.mutable_data<int>(dim_out, Place());
|
||||
|
||||
if (phi::is_gpu_place(Place())) {
|
||||
input_a_cpu.mutable_data<int>(dim_a, phi::CPUPlace());
|
||||
input_b_cpu.mutable_data<int>(dim_b, phi::CPUPlace());
|
||||
out_cpu.mutable_data<int>(dim_out, phi::CPUPlace());
|
||||
}
|
||||
|
||||
int* a_ptr = nullptr;
|
||||
int* b_ptr = nullptr;
|
||||
if (phi::is_gpu_place(Place())) {
|
||||
a_ptr = input_a_cpu.data<int>();
|
||||
b_ptr = input_b_cpu.data<int>();
|
||||
} else {
|
||||
a_ptr = input_a.data<int>();
|
||||
b_ptr = input_b.data<int>();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2 * 3 * 4; ++i) {
|
||||
a_ptr[i] = i;
|
||||
}
|
||||
for (int i = 0; i < 3 * 3 * 4; ++i) {
|
||||
b_ptr[i] = i;
|
||||
}
|
||||
|
||||
if (phi::is_gpu_place(Place())) {
|
||||
paddle::framework::TensorCopySync(input_a_cpu, Place(), &input_a);
|
||||
paddle::framework::TensorCopySync(input_b_cpu, Place(), &input_b);
|
||||
}
|
||||
|
||||
std::vector<phi::DenseTensor> input;
|
||||
input.push_back(input_a);
|
||||
input.push_back(input_b);
|
||||
|
||||
phi::funcs::ConcatFunctor<DeviceContext, int> concat_functor;
|
||||
concat_functor(*context, input, 0, &out);
|
||||
|
||||
// check the dim of input_a, input_b
|
||||
PADDLE_ENFORCE_EQ(input_a.dims(),
|
||||
dim_a,
|
||||
common::errors::InvalidArgument(
|
||||
"The dims of Input tensor should be the same as the "
|
||||
"declared dims. Tensor dims: [%s], declared dims: [%s]",
|
||||
input_a.dims(),
|
||||
dim_a));
|
||||
PADDLE_ENFORCE_EQ(input_b.dims(),
|
||||
dim_b,
|
||||
common::errors::InvalidArgument(
|
||||
"The dims of Input tensor should be the same as the "
|
||||
"declared dims. Tensor dims: [%s], declared dims: [%s]",
|
||||
input_b.dims(),
|
||||
dim_b));
|
||||
|
||||
int* out_ptr = nullptr;
|
||||
if (phi::is_gpu_place(Place())) {
|
||||
paddle::framework::TensorCopySync(out, phi::CPUPlace(), &out_cpu);
|
||||
out_ptr = out_cpu.data<int>();
|
||||
} else {
|
||||
out_ptr = out.data<int>();
|
||||
}
|
||||
|
||||
int cols = 2 * 3 * 4;
|
||||
int idx_a = 0, idx_b = 0;
|
||||
for (int j = 0; j < 5 * 3 * 4; ++j) {
|
||||
if (j >= cols) {
|
||||
PADDLE_ENFORCE_EQ(out_ptr[j],
|
||||
b_ptr[idx_b],
|
||||
common::errors::InvalidArgument(
|
||||
"Concat test failed, the result should be equal."));
|
||||
++idx_b;
|
||||
} else {
|
||||
PADDLE_ENFORCE_EQ(out_ptr[j],
|
||||
a_ptr[idx_a],
|
||||
common::errors::InvalidArgument(
|
||||
"Concat test failed, the result should be equal."));
|
||||
++idx_a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* case 2:
|
||||
* inputs:
|
||||
* t_a.shape: [2, 3, 4]
|
||||
* t_b.shape: [2, 4, 4]
|
||||
* output:
|
||||
* out.shape: [2, 7, 4]
|
||||
*/
|
||||
template <typename DeviceContext, typename Place>
|
||||
void ConcatCase2(DeviceContext* context) {
|
||||
phi::DenseTensor input_a_cpu;
|
||||
phi::DenseTensor input_b_cpu;
|
||||
phi::DenseTensor out_cpu;
|
||||
|
||||
phi::DenseTensor input_a;
|
||||
phi::DenseTensor input_b;
|
||||
phi::DenseTensor out;
|
||||
|
||||
auto dim_a = common::make_ddim({2, 3, 4});
|
||||
auto dim_b = common::make_ddim({2, 4, 4});
|
||||
auto dim_out = common::make_ddim({2, 7, 4});
|
||||
|
||||
input_a.mutable_data<int>(dim_a, Place());
|
||||
input_b.mutable_data<int>(dim_b, Place());
|
||||
out.mutable_data<int>(dim_out, Place());
|
||||
|
||||
if (phi::is_gpu_place(Place())) {
|
||||
input_a_cpu.mutable_data<int>(dim_a, phi::CPUPlace());
|
||||
input_b_cpu.mutable_data<int>(dim_b, phi::CPUPlace());
|
||||
out_cpu.mutable_data<int>(dim_out, phi::CPUPlace());
|
||||
}
|
||||
|
||||
int* a_ptr = nullptr;
|
||||
int* b_ptr = nullptr;
|
||||
if (phi::is_gpu_place(Place())) {
|
||||
a_ptr = input_a_cpu.data<int>();
|
||||
b_ptr = input_b_cpu.data<int>();
|
||||
} else {
|
||||
a_ptr = input_a.data<int>();
|
||||
b_ptr = input_b.data<int>();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2 * 3 * 4; ++i) {
|
||||
a_ptr[i] = i;
|
||||
}
|
||||
for (int i = 0; i < 2 * 4 * 4; ++i) {
|
||||
b_ptr[i] = i;
|
||||
}
|
||||
|
||||
if (phi::is_gpu_place(Place())) {
|
||||
paddle::framework::TensorCopySync(input_a_cpu, Place(), &input_a);
|
||||
paddle::framework::TensorCopySync(input_b_cpu, Place(), &input_b);
|
||||
}
|
||||
|
||||
std::vector<phi::DenseTensor> input;
|
||||
input.push_back(input_a);
|
||||
input.push_back(input_b);
|
||||
|
||||
phi::funcs::ConcatFunctor<DeviceContext, int> concat_functor;
|
||||
concat_functor(*context, input, 1, &out);
|
||||
|
||||
// check the dim of input_a, input_b
|
||||
PADDLE_ENFORCE_EQ(input_a.dims(),
|
||||
dim_a,
|
||||
common::errors::InvalidArgument(
|
||||
"The dims of Input tensor should be the same as the "
|
||||
"declared dims. Tensor dims: [%s], declared dims: [%s]",
|
||||
input_a.dims(),
|
||||
dim_a));
|
||||
PADDLE_ENFORCE_EQ(input_b.dims(),
|
||||
dim_b,
|
||||
common::errors::InvalidArgument(
|
||||
"The dims of Input tensor should be the same as the "
|
||||
"declared dims. Tensor dims: [%s], declared dims: [%s]",
|
||||
input_b.dims(),
|
||||
dim_b));
|
||||
|
||||
int* out_ptr = nullptr;
|
||||
if (phi::is_gpu_place(Place())) {
|
||||
paddle::framework::TensorCopySync(out, phi::CPUPlace(), &out_cpu);
|
||||
out_ptr = out_cpu.data<int>();
|
||||
} else {
|
||||
out_ptr = out.data<int>();
|
||||
}
|
||||
|
||||
int cols = 3 * 4;
|
||||
int idx_a = 0, idx_b = 0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 28; ++j) {
|
||||
if (j >= cols) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
out_ptr[i * 28 + j],
|
||||
b_ptr[idx_b],
|
||||
common::errors::InvalidArgument(
|
||||
"Concat test failed, the result should be equal."));
|
||||
++idx_b;
|
||||
} else {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
out_ptr[i * 28 + j],
|
||||
a_ptr[idx_a],
|
||||
common::errors::InvalidArgument(
|
||||
"Concat test failed, the result should be equal."));
|
||||
++idx_a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* case 3:
|
||||
* inputs:
|
||||
* t_a.shape: [2, 3, 5]
|
||||
* t_b.shape: [2, 3, 4]
|
||||
* output:
|
||||
* out.shape: [2, 3, 9]
|
||||
*/
|
||||
template <typename DeviceContext, typename Place>
|
||||
void ConcatCase3(DeviceContext* context) {
|
||||
phi::DenseTensor input_a_cpu;
|
||||
phi::DenseTensor input_b_cpu;
|
||||
phi::DenseTensor out_cpu;
|
||||
|
||||
phi::DenseTensor input_a;
|
||||
phi::DenseTensor input_b;
|
||||
phi::DenseTensor out;
|
||||
|
||||
auto dim_a = common::make_ddim({2, 3, 4});
|
||||
auto dim_b = common::make_ddim({2, 3, 5});
|
||||
auto dim_out = common::make_ddim({2, 3, 9});
|
||||
|
||||
input_a.mutable_data<int>(dim_a, Place());
|
||||
input_b.mutable_data<int>(dim_b, Place());
|
||||
out.mutable_data<int>(dim_out, Place());
|
||||
|
||||
if (phi::is_gpu_place(Place())) {
|
||||
input_a_cpu.mutable_data<int>(dim_a, phi::CPUPlace());
|
||||
input_b_cpu.mutable_data<int>(dim_b, phi::CPUPlace());
|
||||
out_cpu.mutable_data<int>(dim_out, phi::CPUPlace());
|
||||
}
|
||||
|
||||
int* a_ptr = nullptr;
|
||||
int* b_ptr = nullptr;
|
||||
if (phi::is_gpu_place(Place())) {
|
||||
a_ptr = input_a_cpu.data<int>();
|
||||
b_ptr = input_b_cpu.data<int>();
|
||||
} else {
|
||||
a_ptr = input_a.data<int>();
|
||||
b_ptr = input_b.data<int>();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2 * 3 * 4; ++i) {
|
||||
a_ptr[i] = i;
|
||||
}
|
||||
for (int i = 0; i < 2 * 3 * 5; ++i) {
|
||||
b_ptr[i] = i;
|
||||
}
|
||||
|
||||
if (phi::is_gpu_place(Place())) {
|
||||
paddle::framework::TensorCopySync(input_a_cpu, Place(), &input_a);
|
||||
paddle::framework::TensorCopySync(input_b_cpu, Place(), &input_b);
|
||||
}
|
||||
|
||||
std::vector<phi::DenseTensor> input;
|
||||
input.push_back(input_a);
|
||||
input.push_back(input_b);
|
||||
|
||||
phi::funcs::ConcatFunctor<DeviceContext, int> concat_functor;
|
||||
concat_functor(*context, input, 2, &out);
|
||||
|
||||
// check the dim of input_a, input_b
|
||||
PADDLE_ENFORCE_EQ(input_a.dims(),
|
||||
dim_a,
|
||||
common::errors::InvalidArgument(
|
||||
"The dims of Input tensor should be the same as the "
|
||||
"declared dims. Tensor dims: [%s], declared dims: [%s]",
|
||||
input_a.dims(),
|
||||
dim_a));
|
||||
PADDLE_ENFORCE_EQ(input_b.dims(),
|
||||
dim_b,
|
||||
common::errors::InvalidArgument(
|
||||
"The dims of Input tensor should be the same as the "
|
||||
"declared dims. Tensor dims: [%s], declared dims: [%s]",
|
||||
input_b.dims(),
|
||||
dim_b));
|
||||
|
||||
int* out_ptr = nullptr;
|
||||
if (phi::is_gpu_place(Place())) {
|
||||
paddle::framework::TensorCopySync(out, phi::CPUPlace(), &out_cpu);
|
||||
out_ptr = out_cpu.data<int>();
|
||||
} else {
|
||||
out_ptr = out.data<int>();
|
||||
}
|
||||
|
||||
// check the data
|
||||
int cols = 4;
|
||||
int idx_a = 0, idx_b = 0;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
for (int j = 0; j < 9; ++j) {
|
||||
if (j >= cols) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
out_ptr[i * 9 + j],
|
||||
b_ptr[idx_b],
|
||||
common::errors::InvalidArgument(
|
||||
"Concat test failed, the result should be equal."));
|
||||
++idx_b;
|
||||
} else {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
out_ptr[i * 9 + j],
|
||||
a_ptr[idx_a],
|
||||
common::errors::InvalidArgument(
|
||||
"Concat test failed, the result should be equal."));
|
||||
++idx_a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* case 4:
|
||||
* inputs:
|
||||
* axis = 1
|
||||
* t_a.shape: [2, 3, 4]
|
||||
* t_b.shape: [2, 3, 4]
|
||||
* output:
|
||||
* out.shape: [2, 6, 4]
|
||||
*/
|
||||
template <typename DeviceContext, typename Place>
|
||||
void ConcatCase4(DeviceContext* context) {
|
||||
phi::DenseTensor input_a_cpu;
|
||||
phi::DenseTensor input_b_cpu;
|
||||
phi::DenseTensor out_cpu;
|
||||
|
||||
phi::DenseTensor input_a;
|
||||
phi::DenseTensor input_b;
|
||||
phi::DenseTensor out;
|
||||
|
||||
auto dim_a = common::make_ddim({2, 3, 4});
|
||||
auto dim_b = common::make_ddim({2, 3, 4});
|
||||
auto dim_out = common::make_ddim({2, 6, 4});
|
||||
|
||||
input_a.mutable_data<int>(dim_a, Place());
|
||||
input_b.mutable_data<int>(dim_b, Place());
|
||||
out.mutable_data<int>(dim_out, Place());
|
||||
|
||||
if (phi::is_gpu_place(Place())) {
|
||||
input_a_cpu.mutable_data<int>(dim_a, phi::CPUPlace());
|
||||
input_b_cpu.mutable_data<int>(dim_b, phi::CPUPlace());
|
||||
out_cpu.mutable_data<int>(dim_out, phi::CPUPlace());
|
||||
}
|
||||
|
||||
int* a_ptr = nullptr;
|
||||
int* b_ptr = nullptr;
|
||||
if (phi::is_gpu_place(Place())) {
|
||||
a_ptr = input_a_cpu.data<int>();
|
||||
b_ptr = input_b_cpu.data<int>();
|
||||
} else {
|
||||
a_ptr = input_a.data<int>();
|
||||
b_ptr = input_b.data<int>();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2 * 3 * 4; ++i) {
|
||||
a_ptr[i] = i;
|
||||
}
|
||||
for (int i = 0; i < 2 * 3 * 4; ++i) {
|
||||
b_ptr[i] = i;
|
||||
}
|
||||
|
||||
if (phi::is_gpu_place(Place())) {
|
||||
paddle::framework::TensorCopySync(input_a_cpu, Place(), &input_a);
|
||||
paddle::framework::TensorCopySync(input_b_cpu, Place(), &input_b);
|
||||
}
|
||||
|
||||
std::vector<phi::DenseTensor> input;
|
||||
input.push_back(input_a);
|
||||
input.push_back(input_b);
|
||||
|
||||
phi::funcs::ConcatFunctor<DeviceContext, int> concat_functor;
|
||||
concat_functor(*context, input, 1, &out);
|
||||
context->Wait();
|
||||
|
||||
// check the dim of input_a, input_b
|
||||
PADDLE_ENFORCE_EQ(input_a.dims(),
|
||||
dim_a,
|
||||
common::errors::InvalidArgument(
|
||||
"The dims of Input tensor should be the same as the "
|
||||
"declared dims. Tensor dims: [%s], declared dims: [%s]",
|
||||
input_a.dims(),
|
||||
dim_a));
|
||||
PADDLE_ENFORCE_EQ(input_b.dims(),
|
||||
dim_b,
|
||||
common::errors::InvalidArgument(
|
||||
"The dims of Input tensor should be the same as the "
|
||||
"declared dims. Tensor dims: [%s], declared dims: [%s]",
|
||||
input_b.dims(),
|
||||
dim_b));
|
||||
|
||||
int* out_ptr = nullptr;
|
||||
if (phi::is_gpu_place(Place())) {
|
||||
paddle::framework::TensorCopySync(out, phi::CPUPlace(), &out_cpu);
|
||||
out_ptr = out_cpu.data<int>();
|
||||
} else {
|
||||
out_ptr = out.data<int>();
|
||||
}
|
||||
|
||||
// check the data
|
||||
int cols = 12;
|
||||
int idx_a = 0, idx_b = 0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 24; ++j) {
|
||||
if (j >= cols) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
out_ptr[i * 24 + j],
|
||||
b_ptr[idx_b],
|
||||
common::errors::InvalidArgument(
|
||||
"Concat test failed, the result should be equal."));
|
||||
++idx_b;
|
||||
} else {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
out_ptr[i * 24 + j],
|
||||
a_ptr[idx_a],
|
||||
common::errors::InvalidArgument(
|
||||
"Concat test failed, the result should be equal."));
|
||||
++idx_a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DeviceContext, typename Place>
|
||||
void TestConcatMain() {
|
||||
DeviceContext* context = new DeviceContext(Place());
|
||||
|
||||
ConcatCase1<DeviceContext, Place>(context);
|
||||
ConcatCase2<DeviceContext, Place>(context);
|
||||
ConcatCase3<DeviceContext, Place>(context);
|
||||
ConcatCase4<DeviceContext, Place>(context);
|
||||
|
||||
delete context;
|
||||
}
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
template <>
|
||||
void TestConcatMain<phi::GPUContext, phi::GPUPlace>() {
|
||||
auto* context = new phi::GPUContext(phi::GPUPlace());
|
||||
context->SetAllocator(paddle::memory::allocation::AllocatorFacade::Instance()
|
||||
.GetAllocator(phi::GPUPlace(), context->stream())
|
||||
.get());
|
||||
context->PartialInitWithAllocator();
|
||||
|
||||
ConcatCase1<phi::GPUContext, phi::GPUPlace>(context);
|
||||
ConcatCase2<phi::GPUContext, phi::GPUPlace>(context);
|
||||
ConcatCase3<phi::GPUContext, phi::GPUPlace>(context);
|
||||
ConcatCase4<phi::GPUContext, phi::GPUPlace>(context);
|
||||
|
||||
delete context;
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(math, concat) {
|
||||
TestConcatMain<phi::CPUContext, phi::CPUPlace>();
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
TestConcatMain<phi::GPUContext, phi::GPUPlace>();
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,465 @@
|
||||
/* Copyright (c) 2016 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 "paddle/phi/kernels/funcs/im2col.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <array>
|
||||
|
||||
#include "paddle/fluid/framework/tensor_util.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
#include "paddle/phi/core/platform/device_context.h"
|
||||
#include "paddle/phi/kernels/funcs/im2col_cfo_cpu.h"
|
||||
|
||||
template <typename DeviceContext, typename Place>
|
||||
void testIm2col() {
|
||||
phi::DenseTensor input_tmp;
|
||||
phi::DenseTensor input;
|
||||
phi::DenseTensor output_cfo;
|
||||
phi::DenseTensor output_ocf;
|
||||
phi::DenseTensor output_tmp;
|
||||
|
||||
/**
|
||||
* input = [0, 1, 2,
|
||||
* 3, 4, 5]
|
||||
*
|
||||
* output_cfo = [0, 1
|
||||
* 1, 2
|
||||
* 3, 4
|
||||
* 4, 5]
|
||||
*
|
||||
* output_ocf = [0, 1, 3, 4
|
||||
* 1, 2, 4, 5]
|
||||
*
|
||||
* col2im_cfo = [0, 2, 2
|
||||
* 3, 4, 5]
|
||||
*
|
||||
* col2im_ocf = [0, 2, 2
|
||||
* 3, 4, 5]
|
||||
*/
|
||||
int input_height = 2;
|
||||
int input_width = 3;
|
||||
int filter_size = 2;
|
||||
std::vector<int> stride({1, 1}); // stride_y, stride_x
|
||||
std::vector<int> padding(
|
||||
{0, 0, 0, 0}); // up_pad, left_pad, down_pad, right_pad
|
||||
std::vector<int> dilation({1, 1}); // dilation_y, dilation_x
|
||||
int output_height =
|
||||
(input_height - filter_size + padding[0] + padding[1]) / stride[0] + 1;
|
||||
int output_width =
|
||||
(input_width - filter_size + padding[2] + padding[3]) / stride[1] + 1;
|
||||
float* input_ptr = input_tmp.mutable_data<float>(
|
||||
{1, input_height, input_width}, phi::CPUPlace());
|
||||
std::array<float, 6> arr = {0, 1, 2, 3, 4, 5};
|
||||
memcpy(input_ptr, arr.data(), 6 * sizeof(float));
|
||||
|
||||
auto* place = new Place();
|
||||
DeviceContext* context = new DeviceContext(*place);
|
||||
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
input = input_tmp;
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(input_tmp, *place, &input);
|
||||
}
|
||||
output_cfo.mutable_data<float>(
|
||||
{1, filter_size, filter_size, output_height, output_width}, *place);
|
||||
output_ocf.mutable_data<float>(
|
||||
{output_height, output_width, 1, filter_size, filter_size}, *place);
|
||||
|
||||
// Im2Col
|
||||
phi::funcs::Im2ColFunctor<phi::funcs::ColFormat::CFO, DeviceContext, float>
|
||||
im2col;
|
||||
phi::funcs::Im2ColFunctor<phi::funcs::ColFormat::OCF, DeviceContext, float>
|
||||
im2col_ocf;
|
||||
|
||||
im2col(*context, input, dilation, stride, padding, &output_cfo);
|
||||
im2col_ocf(*context, input, dilation, stride, padding, &output_ocf);
|
||||
|
||||
std::array<float, 8> out_cfo_data = {0, 1, 1, 2, 3, 4, 4, 5};
|
||||
std::array<float, 8> out_ocf_data = {0, 1, 3, 4, 1, 2, 4, 5};
|
||||
|
||||
float* out_cfo_ptr = nullptr;
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
out_cfo_ptr = output_cfo.data<float>();
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(output_cfo, phi::CPUPlace(), &output_tmp);
|
||||
out_cfo_ptr = output_tmp.data<float>();
|
||||
}
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
EXPECT_EQ(out_cfo_ptr[i], out_cfo_data[i]);
|
||||
}
|
||||
|
||||
float* out_ocf_ptr = nullptr;
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
out_ocf_ptr = output_ocf.data<float>();
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(output_ocf, phi::CPUPlace(), &output_tmp);
|
||||
out_ocf_ptr = output_tmp.data<float>();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
EXPECT_EQ(out_ocf_ptr[i], out_ocf_data[i]);
|
||||
}
|
||||
|
||||
// Col2Im: CFO
|
||||
phi::funcs::Col2ImFunctor<phi::funcs::ColFormat::CFO, DeviceContext, float>
|
||||
col2im;
|
||||
phi::funcs::Col2ImFunctor<phi::funcs::ColFormat::OCF, DeviceContext, float>
|
||||
col2im_ocf;
|
||||
std::array<float, 6> col2im_data = {0, 2, 2, 3, 8, 5};
|
||||
|
||||
memset(input_ptr, 0, 6 * sizeof(float));
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
input = input_tmp;
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(input_tmp, *place, &input);
|
||||
}
|
||||
|
||||
col2im(*context, output_cfo, dilation, stride, padding, &input);
|
||||
|
||||
float* in_ptr = nullptr;
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
in_ptr = input.data<float>();
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(input, phi::CPUPlace(), &input_tmp);
|
||||
in_ptr = input_tmp.data<float>();
|
||||
}
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
EXPECT_EQ(in_ptr[i], col2im_data[i]);
|
||||
}
|
||||
|
||||
// Col2Im: OCF
|
||||
memset(input_ptr, 0, 6 * sizeof(float));
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
input = input_tmp;
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(input_tmp, *place, &input);
|
||||
}
|
||||
|
||||
col2im_ocf(*context, output_ocf, dilation, stride, padding, &input);
|
||||
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
in_ptr = input.data<float>();
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(input, phi::CPUPlace(), &input_tmp);
|
||||
in_ptr = input_tmp.data<float>();
|
||||
}
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
EXPECT_EQ(in_ptr[i], col2im_data[i]);
|
||||
}
|
||||
|
||||
delete place;
|
||||
delete context;
|
||||
}
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
template <>
|
||||
void testIm2col<phi::GPUContext, phi::GPUPlace>() {
|
||||
phi::DenseTensor input_tmp;
|
||||
phi::DenseTensor input;
|
||||
phi::DenseTensor output_cfo;
|
||||
phi::DenseTensor output_ocf;
|
||||
phi::DenseTensor output_tmp;
|
||||
|
||||
/**
|
||||
* input = [0, 1, 2,
|
||||
* 3, 4, 5]
|
||||
*
|
||||
* output_cfo = [0, 1
|
||||
* 1, 2
|
||||
* 3, 4
|
||||
* 4, 5]
|
||||
*
|
||||
* output_ocf = [0, 1, 3, 4
|
||||
* 1, 2, 4, 5]
|
||||
*
|
||||
* col2im_cfo = [0, 2, 2
|
||||
* 3, 4, 5]
|
||||
*
|
||||
* col2im_ocf = [0, 2, 2
|
||||
* 3, 4, 5]
|
||||
*/
|
||||
int input_height = 2;
|
||||
int input_width = 3;
|
||||
int filter_size = 2;
|
||||
std::vector<int> stride({1, 1}); // stride_y, stride_x
|
||||
std::vector<int> padding(
|
||||
{0, 0, 0, 0}); // up_pad, left_pad, down_pad, right_pad
|
||||
std::vector<int> dilation({1, 1}); // dilation_y, dilation_x
|
||||
int output_height =
|
||||
(input_height - filter_size + padding[0] + padding[1]) / stride[0] + 1;
|
||||
int output_width =
|
||||
(input_width - filter_size + padding[2] + padding[3]) / stride[1] + 1;
|
||||
float* input_ptr = input_tmp.mutable_data<float>(
|
||||
{1, input_height, input_width}, phi::CPUPlace());
|
||||
std::array<float, 6> arr = {0, 1, 2, 3, 4, 5};
|
||||
memcpy(input_ptr, arr.data(), 6 * sizeof(float));
|
||||
|
||||
auto* place = new phi::GPUPlace();
|
||||
auto* context = new phi::GPUContext(*place);
|
||||
context->SetAllocator(paddle::memory::allocation::AllocatorFacade::Instance()
|
||||
.GetAllocator(*place, context->stream())
|
||||
.get());
|
||||
context->PartialInitWithAllocator();
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
input = input_tmp;
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(input_tmp, *place, &input);
|
||||
}
|
||||
output_cfo.mutable_data<float>(
|
||||
{1, filter_size, filter_size, output_height, output_width}, *place);
|
||||
output_ocf.mutable_data<float>(
|
||||
{output_height, output_width, 1, filter_size, filter_size}, *place);
|
||||
|
||||
// Im2Col
|
||||
phi::funcs::Im2ColFunctor<phi::funcs::ColFormat::CFO, phi::GPUContext, float>
|
||||
im2col;
|
||||
phi::funcs::Im2ColFunctor<phi::funcs::ColFormat::OCF, phi::GPUContext, float>
|
||||
im2col_ocf;
|
||||
|
||||
im2col(*context, input, dilation, stride, padding, &output_cfo);
|
||||
im2col_ocf(*context, input, dilation, stride, padding, &output_ocf);
|
||||
|
||||
std::array<float, 8> out_cfo_data = {0, 1, 1, 2, 3, 4, 4, 5};
|
||||
std::array<float, 8> out_ocf_data = {0, 1, 3, 4, 1, 2, 4, 5};
|
||||
|
||||
float* out_cfo_ptr;
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
out_cfo_ptr = output_cfo.data<float>();
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(output_cfo, phi::CPUPlace(), &output_tmp);
|
||||
out_cfo_ptr = output_tmp.data<float>();
|
||||
}
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
EXPECT_EQ(out_cfo_ptr[i], out_cfo_data[i]);
|
||||
}
|
||||
|
||||
float* out_ocf_ptr;
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
out_ocf_ptr = output_ocf.data<float>();
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(output_ocf, phi::CPUPlace(), &output_tmp);
|
||||
out_ocf_ptr = output_tmp.data<float>();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
EXPECT_EQ(out_ocf_ptr[i], out_ocf_data[i]);
|
||||
}
|
||||
|
||||
// Col2Im: CFO
|
||||
phi::funcs::Col2ImFunctor<phi::funcs::ColFormat::CFO, phi::GPUContext, float>
|
||||
col2im;
|
||||
phi::funcs::Col2ImFunctor<phi::funcs::ColFormat::OCF, phi::GPUContext, float>
|
||||
col2im_ocf;
|
||||
std::array<float, 6> col2im_data = {0, 2, 2, 3, 8, 5};
|
||||
|
||||
memset(input_ptr, 0, 6 * sizeof(float));
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
input = input_tmp;
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(input_tmp, *place, &input);
|
||||
}
|
||||
|
||||
col2im(*context, output_cfo, dilation, stride, padding, &input);
|
||||
|
||||
float* in_ptr;
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
in_ptr = input.data<float>();
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(input, phi::CPUPlace(), &input_tmp);
|
||||
in_ptr = input_tmp.data<float>();
|
||||
}
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
EXPECT_EQ(in_ptr[i], col2im_data[i]);
|
||||
}
|
||||
|
||||
// Col2Im: OCF
|
||||
memset(input_ptr, 0, 6 * sizeof(float));
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
input = input_tmp;
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(input_tmp, *place, &input);
|
||||
}
|
||||
|
||||
col2im_ocf(*context, output_ocf, dilation, stride, padding, &input);
|
||||
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
in_ptr = input.data<float>();
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(input, phi::CPUPlace(), &input_tmp);
|
||||
in_ptr = input_tmp.data<float>();
|
||||
}
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
EXPECT_EQ(in_ptr[i], col2im_data[i]);
|
||||
}
|
||||
|
||||
delete place;
|
||||
delete context;
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(math, im2col) {
|
||||
testIm2col<phi::CPUContext, phi::CPUPlace>();
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
testIm2col<phi::GPUContext, phi::GPUPlace>();
|
||||
#endif
|
||||
}
|
||||
|
||||
#define PREPARE_IM2COL_CPU \
|
||||
phi::CPUPlace place; \
|
||||
phi::CPUContext context(place); \
|
||||
phi::DenseTensor input; \
|
||||
phi::DenseTensor out; \
|
||||
phi::DenseTensor 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); \
|
||||
phi::funcs:: \
|
||||
Im2ColFunctor<phi::funcs::ColFormat::CFO, phi::CPUContext, 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);
|
||||
phi::funcs::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 = {0, 0};
|
||||
gettimeofday(&time, nullptr);
|
||||
return 1e+3 * time.tv_sec + 1e-3 * time.tv_usec; // NOLINT
|
||||
};
|
||||
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) {
|
||||
phi::funcs::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,518 @@
|
||||
/* Copyright (c) 2016 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 "paddle/phi/kernels/funcs/selected_rows_functor.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "paddle/phi/core/memory/allocation/allocator_facade.h"
|
||||
#include "paddle/phi/kernels/funcs/math_function.h"
|
||||
|
||||
TEST(selected_rows_functor, cpu_add) {
|
||||
phi::CPUPlace cpu_place;
|
||||
phi::CPUContext ctx(cpu_place);
|
||||
ctx.SetAllocator(paddle::memory::allocation::AllocatorFacade::Instance()
|
||||
.GetAllocator(cpu_place)
|
||||
.get());
|
||||
phi::funcs::SetConstant<phi::CPUContext, float> functor;
|
||||
int64_t height = 10;
|
||||
int64_t row_numel = 10;
|
||||
|
||||
std::vector<int64_t> rows1{0, 4, 7};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows1{
|
||||
new phi::SelectedRows(rows1, height)};
|
||||
auto* in1_value = selected_rows1->mutable_value();
|
||||
in1_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows1.size()), row_numel}),
|
||||
cpu_place);
|
||||
functor(ctx, in1_value, 1.0);
|
||||
|
||||
std::vector<int64_t> rows2{0, 5, 7, 9};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows2{
|
||||
new phi::SelectedRows(rows2, height)};
|
||||
auto* in2_value = selected_rows2->mutable_value();
|
||||
in2_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows2.size()), row_numel}),
|
||||
cpu_place);
|
||||
functor(ctx, in2_value, 2.0);
|
||||
|
||||
std::unique_ptr<phi::SelectedRows> output{new phi::SelectedRows()};
|
||||
auto* out_value = output->mutable_value();
|
||||
|
||||
// simply concat two SelectedRows
|
||||
out_value->mutable_data<float>(common::make_ddim({7, 10}), cpu_place);
|
||||
|
||||
phi::funcs::SelectedRowsAdd<phi::CPUContext, float> add_functor;
|
||||
add_functor(ctx, *selected_rows1, *selected_rows2, output.get());
|
||||
|
||||
auto out_height = output->height();
|
||||
EXPECT_EQ(out_height, height);
|
||||
|
||||
auto& out_rows = output->rows();
|
||||
|
||||
// input1 rows
|
||||
EXPECT_EQ(out_rows[0], 0);
|
||||
EXPECT_EQ(out_rows[1], 4);
|
||||
EXPECT_EQ(out_rows[2], 7);
|
||||
// input2 rows
|
||||
EXPECT_EQ(out_rows[3], 0);
|
||||
EXPECT_EQ(out_rows[4], 5);
|
||||
EXPECT_EQ(out_rows[5], 7);
|
||||
EXPECT_EQ(out_rows[6], 9);
|
||||
|
||||
auto* out_data = output->value().data<float>();
|
||||
// input1 value
|
||||
EXPECT_EQ(out_data[0 * row_numel + 0], 1.0);
|
||||
EXPECT_EQ(out_data[0 * row_numel + 8], 1.0);
|
||||
EXPECT_EQ(out_data[1 * row_numel + 1], 1.0);
|
||||
EXPECT_EQ(out_data[2 * row_numel + 6], 1.0);
|
||||
// input2 value
|
||||
EXPECT_EQ(out_data[3 * row_numel + 3], 2.0);
|
||||
EXPECT_EQ(out_data[3 * row_numel + 8], 2.0);
|
||||
EXPECT_EQ(out_data[4 * row_numel + 4], 2.0);
|
||||
EXPECT_EQ(out_data[5 * row_numel + 7], 2.0);
|
||||
EXPECT_EQ(out_data[6 * row_numel + 9], 2.0);
|
||||
|
||||
std::unique_ptr<phi::DenseTensor> tensor1{new phi::DenseTensor()};
|
||||
tensor1->mutable_data<float>(common::make_ddim({height, row_numel}),
|
||||
cpu_place);
|
||||
functor(ctx, tensor1.get(), 3.0);
|
||||
|
||||
std::unique_ptr<phi::DenseTensor> tensor2{new phi::DenseTensor()};
|
||||
tensor2->mutable_data<float>(common::make_ddim({height, row_numel}),
|
||||
cpu_place);
|
||||
|
||||
phi::funcs::SelectedRowsAddTensor<phi::CPUContext, float> add_tensor_functor;
|
||||
add_tensor_functor(ctx, *output, *tensor1, tensor2.get());
|
||||
|
||||
auto* tensor2_data = tensor2->data<float>();
|
||||
// row0: 1.0 + 2.0 + 3.0
|
||||
EXPECT_EQ(tensor2_data[0 * row_numel + 0], 6.0);
|
||||
// row1: 3.0
|
||||
EXPECT_EQ(tensor2_data[1 * row_numel + 1], 3.0);
|
||||
// row4 : 1.0 + 3.0
|
||||
EXPECT_EQ(tensor2_data[4 * row_numel + 6], 4.0);
|
||||
// row5: 2.0 + 3.0
|
||||
EXPECT_EQ(tensor2_data[5 * row_numel + 7], 5.0);
|
||||
// row6: 3.0
|
||||
EXPECT_EQ(tensor2_data[6 * row_numel + 1], 3.0);
|
||||
// row7: 1.0 + 2.0 + 3.0
|
||||
EXPECT_EQ(tensor2_data[7 * row_numel + 3], 6.0);
|
||||
// row9: 2.0 + 3.0
|
||||
EXPECT_EQ(tensor2_data[9 * row_numel + 6], 5.0);
|
||||
}
|
||||
|
||||
TEST(selected_rows_functor, cpu_add_to) {
|
||||
phi::CPUPlace cpu_place;
|
||||
phi::CPUContext ctx(cpu_place);
|
||||
ctx.SetAllocator(paddle::memory::allocation::AllocatorFacade::Instance()
|
||||
.GetAllocator(cpu_place)
|
||||
.get());
|
||||
phi::funcs::SetConstant<phi::CPUContext, float> functor;
|
||||
int64_t height = 10;
|
||||
int64_t row_numel = 10;
|
||||
|
||||
std::vector<int64_t> rows1{0, 4, 7};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows1{
|
||||
new phi::SelectedRows(rows1, height)};
|
||||
auto* in1_value = selected_rows1->mutable_value();
|
||||
in1_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows1.size()), row_numel}),
|
||||
cpu_place);
|
||||
functor(ctx, in1_value, 1.0);
|
||||
|
||||
std::vector<int64_t> rows2{0, 5, 7, 9};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows2{
|
||||
new phi::SelectedRows(rows2, height)};
|
||||
auto* in2_value = selected_rows2->mutable_value();
|
||||
in2_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows2.size()), row_numel}),
|
||||
cpu_place);
|
||||
functor(ctx, in2_value, 2.0);
|
||||
|
||||
std::unique_ptr<phi::SelectedRows> output{new phi::SelectedRows()};
|
||||
output->set_height(height);
|
||||
auto* out_value = output->mutable_value();
|
||||
|
||||
// simply concat two SelectedRows
|
||||
out_value->mutable_data<float>(common::make_ddim({7, 10}), cpu_place);
|
||||
|
||||
phi::funcs::SelectedRowsAddTo<phi::CPUContext, float> add_to_functor;
|
||||
add_to_functor(ctx, *selected_rows1, 0, output.get());
|
||||
add_to_functor(ctx, *selected_rows2, in1_value->numel(), output.get());
|
||||
|
||||
auto out_height = output->height();
|
||||
EXPECT_EQ(out_height, height);
|
||||
|
||||
auto& out_rows = output->rows();
|
||||
|
||||
// input1 rows
|
||||
EXPECT_EQ(out_rows[0], 0);
|
||||
EXPECT_EQ(out_rows[1], 4);
|
||||
EXPECT_EQ(out_rows[2], 7);
|
||||
// input2 rows
|
||||
EXPECT_EQ(out_rows[3], 0);
|
||||
EXPECT_EQ(out_rows[4], 5);
|
||||
EXPECT_EQ(out_rows[5], 7);
|
||||
EXPECT_EQ(out_rows[6], 9);
|
||||
|
||||
auto* out_data = output->value().data<float>();
|
||||
// input1 value
|
||||
EXPECT_EQ(out_data[0 * row_numel + 0], 1.0);
|
||||
EXPECT_EQ(out_data[0 * row_numel + 8], 1.0);
|
||||
EXPECT_EQ(out_data[1 * row_numel + 1], 1.0);
|
||||
EXPECT_EQ(out_data[2 * row_numel + 6], 1.0);
|
||||
// input2 value
|
||||
EXPECT_EQ(out_data[3 * row_numel + 3], 2.0);
|
||||
EXPECT_EQ(out_data[3 * row_numel + 8], 2.0);
|
||||
EXPECT_EQ(out_data[4 * row_numel + 4], 2.0);
|
||||
EXPECT_EQ(out_data[5 * row_numel + 7], 2.0);
|
||||
EXPECT_EQ(out_data[6 * row_numel + 9], 2.0);
|
||||
|
||||
std::unique_ptr<phi::DenseTensor> tensor1{new phi::DenseTensor()};
|
||||
tensor1->mutable_data<float>(common::make_ddim({height, row_numel}),
|
||||
cpu_place);
|
||||
functor(ctx, tensor1.get(), 3.0);
|
||||
|
||||
phi::funcs::SelectedRowsAddToTensor<phi::CPUContext, float>
|
||||
add_to_tensor_functor;
|
||||
add_to_tensor_functor(ctx, *output, tensor1.get());
|
||||
|
||||
auto* tensor1_data = tensor1->data<float>();
|
||||
// row0: 1.0 + 2.0 + 3.0
|
||||
EXPECT_EQ(tensor1_data[0 * row_numel + 0], 6.0);
|
||||
// row1: 3.0
|
||||
EXPECT_EQ(tensor1_data[1 * row_numel + 1], 3.0);
|
||||
// row4 : 1.0 + 3.0
|
||||
EXPECT_EQ(tensor1_data[4 * row_numel + 6], 4.0);
|
||||
// row5: 2.0 + 3.0
|
||||
EXPECT_EQ(tensor1_data[5 * row_numel + 7], 5.0);
|
||||
// row6: 3.0
|
||||
EXPECT_EQ(tensor1_data[6 * row_numel + 1], 3.0);
|
||||
// row7: 1.0 + 2.0 + 3.0
|
||||
EXPECT_EQ(tensor1_data[7 * row_numel + 3], 6.0);
|
||||
// row9: 2.0 + 3.0
|
||||
EXPECT_EQ(tensor1_data[9 * row_numel + 6], 5.0);
|
||||
}
|
||||
|
||||
TEST(selected_rows_functor, cpu_merge_average_float) {
|
||||
phi::CPUPlace cpu_place;
|
||||
phi::CPUContext ctx(cpu_place);
|
||||
ctx.SetAllocator(paddle::memory::allocation::AllocatorFacade::Instance()
|
||||
.GetAllocator(cpu_place)
|
||||
.get());
|
||||
phi::funcs::SetConstant<phi::CPUContext, float> functor;
|
||||
int64_t height = 10;
|
||||
int64_t row_numel = 10;
|
||||
|
||||
std::vector<int64_t> rows{0, 4, 4, 7};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows{
|
||||
new phi::SelectedRows(rows, height)};
|
||||
auto* in_value = selected_rows->mutable_value();
|
||||
in_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows.size()), row_numel}),
|
||||
cpu_place);
|
||||
functor(ctx, in_value, 1.0);
|
||||
|
||||
phi::funcs::scatter::MergeAverage<phi::CPUContext, float>
|
||||
merge_average_functor;
|
||||
phi::SelectedRows output = merge_average_functor(ctx, *selected_rows);
|
||||
|
||||
auto out_height = output.height();
|
||||
EXPECT_EQ(out_height, height);
|
||||
|
||||
auto& out_rows = output.rows();
|
||||
EXPECT_EQ(out_rows[0], 0);
|
||||
EXPECT_EQ(out_rows[1], 4);
|
||||
EXPECT_EQ(out_rows[2], 7);
|
||||
|
||||
auto* out_data = output.value().data<float>();
|
||||
|
||||
EXPECT_EQ(out_data[0 * row_numel], 1.0);
|
||||
EXPECT_EQ(out_data[1 * row_numel], 2.0);
|
||||
EXPECT_EQ(out_data[2 * row_numel], 1.0);
|
||||
}
|
||||
|
||||
TEST(selected_rows_functor, cpu_merge_add_float) {
|
||||
phi::CPUPlace cpu_place;
|
||||
phi::CPUContext ctx(cpu_place);
|
||||
ctx.SetAllocator(paddle::memory::allocation::AllocatorFacade::Instance()
|
||||
.GetAllocator(cpu_place)
|
||||
.get());
|
||||
phi::funcs::SetConstant<phi::CPUContext, float> functor;
|
||||
int64_t height = 10;
|
||||
int64_t row_numel = 10;
|
||||
|
||||
std::vector<int64_t> rows{0, 4, 4, 7};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows{
|
||||
new phi::SelectedRows(rows, height)};
|
||||
auto* in_value = selected_rows->mutable_value();
|
||||
in_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows.size()), row_numel}),
|
||||
cpu_place);
|
||||
functor(ctx, in_value, 1.0);
|
||||
|
||||
std::unique_ptr<phi::SelectedRows> output{new phi::SelectedRows()};
|
||||
|
||||
phi::funcs::scatter::MergeAdd<phi::CPUContext, float> merge_add_functor;
|
||||
merge_add_functor(ctx, *selected_rows, output.get());
|
||||
|
||||
auto out_height = output->height();
|
||||
EXPECT_EQ(out_height, height);
|
||||
|
||||
auto& out_rows = output->rows();
|
||||
EXPECT_EQ(out_rows[0], 0);
|
||||
EXPECT_EQ(out_rows[1], 4);
|
||||
EXPECT_EQ(out_rows[2], 7);
|
||||
|
||||
auto* out_data = output->value().data<float>();
|
||||
|
||||
EXPECT_EQ(out_data[0 * row_numel], 1.0);
|
||||
EXPECT_EQ(out_data[1 * row_numel], 2.0);
|
||||
EXPECT_EQ(out_data[2 * row_numel], 1.0);
|
||||
}
|
||||
|
||||
TEST(selected_rows_functor, cpu_merge_add_int) {
|
||||
phi::CPUPlace cpu_place;
|
||||
phi::CPUContext ctx(cpu_place);
|
||||
ctx.SetAllocator(paddle::memory::allocation::AllocatorFacade::Instance()
|
||||
.GetAllocator(cpu_place)
|
||||
.get());
|
||||
phi::funcs::SetConstant<phi::CPUContext, int> functor;
|
||||
int64_t height = 10;
|
||||
int64_t row_numel = 10;
|
||||
|
||||
std::vector<int64_t> rows{0, 4, 4, 7};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows{
|
||||
new phi::SelectedRows(rows, height)};
|
||||
auto* in_value = selected_rows->mutable_value();
|
||||
in_value->mutable_data<int>(
|
||||
common::make_ddim({static_cast<int64_t>(rows.size()), row_numel}),
|
||||
cpu_place);
|
||||
functor(ctx, in_value, 1);
|
||||
|
||||
std::unique_ptr<phi::SelectedRows> output{new phi::SelectedRows()};
|
||||
|
||||
phi::funcs::scatter::MergeAdd<phi::CPUContext, int> merge_add_functor;
|
||||
merge_add_functor(ctx, *selected_rows, output.get());
|
||||
|
||||
auto out_height = output->height();
|
||||
EXPECT_EQ(out_height, height);
|
||||
|
||||
auto& out_rows = output->rows();
|
||||
EXPECT_EQ(out_rows[0], 0);
|
||||
EXPECT_EQ(out_rows[1], 4);
|
||||
EXPECT_EQ(out_rows[2], 7);
|
||||
|
||||
auto* out_data = output->value().data<int>();
|
||||
|
||||
EXPECT_EQ(out_data[0 * row_numel], 1);
|
||||
EXPECT_EQ(out_data[1 * row_numel], 2);
|
||||
EXPECT_EQ(out_data[2 * row_numel], 1);
|
||||
}
|
||||
|
||||
TEST(selected_rows_functor, cpu_merge_add_multi) {
|
||||
phi::CPUPlace cpu_place;
|
||||
phi::CPUContext ctx(cpu_place);
|
||||
ctx.SetAllocator(paddle::memory::allocation::AllocatorFacade::Instance()
|
||||
.GetAllocator(cpu_place)
|
||||
.get());
|
||||
phi::funcs::SetConstant<phi::CPUContext, float> set_const;
|
||||
|
||||
int64_t height = 10;
|
||||
int64_t row_numel = 8;
|
||||
|
||||
std::vector<int64_t> rows1{5, 2, 5, 3, 5};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows1{
|
||||
new phi::SelectedRows(rows1, height)};
|
||||
auto* in1_value = selected_rows1->mutable_value();
|
||||
in1_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows1.size()), row_numel}),
|
||||
cpu_place);
|
||||
set_const(ctx, in1_value, 1.0);
|
||||
|
||||
std::vector<int64_t> rows2{2, 5, 3, 5, 3};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows2{
|
||||
new phi::SelectedRows(rows2, height)};
|
||||
auto* in2_value = selected_rows2->mutable_value();
|
||||
in2_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows2.size()), row_numel}),
|
||||
cpu_place);
|
||||
set_const(ctx, in2_value, 1.0);
|
||||
|
||||
std::unique_ptr<phi::SelectedRows> output{new phi::SelectedRows()};
|
||||
output->set_height(height);
|
||||
phi::funcs::scatter::MergeAdd<phi::CPUContext, float> merge_add_functor;
|
||||
|
||||
std::vector<const phi::SelectedRows*> inputs;
|
||||
inputs.push_back(selected_rows1.get());
|
||||
inputs.push_back(selected_rows2.get());
|
||||
merge_add_functor(ctx, inputs, output.get());
|
||||
|
||||
EXPECT_EQ(output->height(), height);
|
||||
EXPECT_EQ(output->value().dims(), common::make_ddim({3, row_numel}));
|
||||
|
||||
std::vector<int64_t> ret_rows{2, 3, 5};
|
||||
EXPECT_EQ(output->rows(), ret_rows);
|
||||
|
||||
auto* out_data = output->value().data<float>();
|
||||
for (size_t i = 0; i < ret_rows.size(); ++i) {
|
||||
for (size_t j = 0; j < static_cast<size_t>(row_numel); ++j) {
|
||||
EXPECT_EQ(out_data[i * row_numel + j], ret_rows[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(selected_rows_functor, cpu_merge_add_multi_noduplicated) {
|
||||
phi::CPUPlace cpu_place;
|
||||
phi::CPUContext ctx(cpu_place);
|
||||
ctx.SetAllocator(paddle::memory::allocation::AllocatorFacade::Instance()
|
||||
.GetAllocator(cpu_place)
|
||||
.get());
|
||||
phi::funcs::SetConstant<phi::CPUContext, float> set_const;
|
||||
|
||||
int64_t height = 10;
|
||||
int64_t row_numel = 8;
|
||||
|
||||
std::vector<int64_t> rows1{1, 3, 5, 7, 9};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows1{
|
||||
new phi::SelectedRows(rows1, height)};
|
||||
auto* in1_value = selected_rows1->mutable_value();
|
||||
in1_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows1.size()), row_numel}),
|
||||
cpu_place);
|
||||
set_const(ctx, in1_value, 1.0);
|
||||
|
||||
std::vector<int64_t> rows2{0, 2, 4, 6, 8};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows2{
|
||||
new phi::SelectedRows(rows2, height)};
|
||||
auto* in2_value = selected_rows2->mutable_value();
|
||||
in2_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows2.size()), row_numel}),
|
||||
cpu_place);
|
||||
set_const(ctx, in2_value, 2.0);
|
||||
|
||||
std::unique_ptr<phi::SelectedRows> output{new phi::SelectedRows()};
|
||||
output->set_height(height);
|
||||
phi::funcs::scatter::MergeAdd<phi::CPUContext, float> merge_add_functor;
|
||||
|
||||
std::vector<const phi::SelectedRows*> inputs;
|
||||
inputs.push_back(selected_rows1.get());
|
||||
inputs.push_back(selected_rows2.get());
|
||||
merge_add_functor(ctx, inputs, output.get());
|
||||
|
||||
EXPECT_EQ(output->height(), height);
|
||||
EXPECT_EQ(output->value().dims(), common::make_ddim({10, row_numel}));
|
||||
|
||||
std::vector<int64_t> ret_rows{1, 3, 5, 7, 9, 0, 2, 4, 6, 8};
|
||||
EXPECT_EQ(output->rows(), ret_rows);
|
||||
|
||||
auto* out_data = output->value().data<float>();
|
||||
for (size_t i = 0; i < ret_rows.size(); ++i) {
|
||||
float data_value = 0;
|
||||
if (i < 5) {
|
||||
data_value = 1.0;
|
||||
} else {
|
||||
data_value = 2.0;
|
||||
}
|
||||
for (size_t j = 0; j < static_cast<size_t>(row_numel); ++j) {
|
||||
EXPECT_EQ(out_data[i * row_numel + j], data_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(selected_rows_functor, cpu_sum_to) {
|
||||
phi::CPUPlace cpu_place;
|
||||
phi::CPUContext ctx(cpu_place);
|
||||
ctx.SetAllocator(paddle::memory::allocation::AllocatorFacade::Instance()
|
||||
.GetAllocator(cpu_place)
|
||||
.get());
|
||||
phi::funcs::SetConstant<phi::CPUContext, float> functor;
|
||||
int64_t height = 10;
|
||||
int64_t row_numel = 10;
|
||||
std::vector<int64_t> rows1{0, 4, 7};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows1{
|
||||
new phi::SelectedRows(rows1, height)};
|
||||
auto* in1_value = selected_rows1->mutable_value();
|
||||
in1_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows1.size()), row_numel}),
|
||||
cpu_place);
|
||||
|
||||
functor(ctx, in1_value, 1.0);
|
||||
std::vector<int64_t> rows2{0, 5, 7, 9};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows2{
|
||||
new phi::SelectedRows(rows2, height)};
|
||||
auto* in2_value = selected_rows2->mutable_value();
|
||||
in2_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows2.size()), row_numel}),
|
||||
cpu_place);
|
||||
|
||||
functor(ctx, in2_value, 2.0);
|
||||
std::unique_ptr<phi::SelectedRows> output{new phi::SelectedRows()};
|
||||
output->set_height(height);
|
||||
auto* out_value = output->mutable_value();
|
||||
// simply concat two SelectedRows
|
||||
out_value->mutable_data<float>(common::make_ddim({7, 10}), cpu_place);
|
||||
phi::funcs::SelectedRowsSumTo<phi::CPUContext, float> sum_to_functor;
|
||||
sum_to_functor(ctx,
|
||||
std::vector<phi::SelectedRows*>(
|
||||
{selected_rows1.get(), selected_rows2.get()}),
|
||||
std::vector<int64_t>({0, in1_value->numel()}),
|
||||
output.get());
|
||||
auto out_height = output->height();
|
||||
EXPECT_EQ(out_height, height);
|
||||
auto& out_rows = output->rows();
|
||||
// input1 rows
|
||||
EXPECT_EQ(out_rows[0], 0);
|
||||
EXPECT_EQ(out_rows[1], 4);
|
||||
EXPECT_EQ(out_rows[2], 7);
|
||||
// input2 rows
|
||||
EXPECT_EQ(out_rows[3], 0);
|
||||
EXPECT_EQ(out_rows[4], 5);
|
||||
EXPECT_EQ(out_rows[5], 7);
|
||||
EXPECT_EQ(out_rows[6], 9);
|
||||
auto* out_data = output->value().data<float>();
|
||||
// input1 value
|
||||
EXPECT_EQ(out_data[0 * row_numel + 0], 1.0);
|
||||
EXPECT_EQ(out_data[0 * row_numel + 8], 1.0);
|
||||
EXPECT_EQ(out_data[1 * row_numel + 1], 1.0);
|
||||
EXPECT_EQ(out_data[2 * row_numel + 6], 1.0);
|
||||
// input2 value
|
||||
EXPECT_EQ(out_data[3 * row_numel + 3], 2.0);
|
||||
EXPECT_EQ(out_data[3 * row_numel + 8], 2.0);
|
||||
EXPECT_EQ(out_data[4 * row_numel + 4], 2.0);
|
||||
EXPECT_EQ(out_data[5 * row_numel + 7], 2.0);
|
||||
EXPECT_EQ(out_data[6 * row_numel + 9], 2.0);
|
||||
std::unique_ptr<phi::DenseTensor> tensor1{new phi::DenseTensor()};
|
||||
tensor1->mutable_data<float>(common::make_ddim({height, row_numel}),
|
||||
cpu_place);
|
||||
functor(ctx, tensor1.get(), 3.0);
|
||||
phi::funcs::SelectedRowsAddToTensor<phi::CPUContext, float>
|
||||
add_to_tensor_functor;
|
||||
add_to_tensor_functor(ctx, *output, tensor1.get());
|
||||
auto* tensor1_data = tensor1->data<float>();
|
||||
// row0: 1.0 + 2.0 + 3.0
|
||||
EXPECT_EQ(tensor1_data[0 * row_numel + 0], 6.0);
|
||||
// row1: 3.0
|
||||
EXPECT_EQ(tensor1_data[1 * row_numel + 1], 3.0);
|
||||
// row4 : 1.0 + 3.0
|
||||
EXPECT_EQ(tensor1_data[4 * row_numel + 6], 4.0);
|
||||
// row5: 2.0 + 3.0
|
||||
EXPECT_EQ(tensor1_data[5 * row_numel + 7], 5.0);
|
||||
// row6: 3.0
|
||||
EXPECT_EQ(tensor1_data[6 * row_numel + 1], 3.0);
|
||||
// row7: 1.0 + 2.0 + 3.0
|
||||
EXPECT_EQ(tensor1_data[7 * row_numel + 3], 6.0);
|
||||
// row9: 2.0 + 3.0
|
||||
EXPECT_EQ(tensor1_data[9 * row_numel + 6], 5.0);
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
/* Copyright (c) 2016 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 "paddle/phi/kernels/funcs/selected_rows_functor.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "paddle/common/errors.h"
|
||||
#include "paddle/phi/backends/context_pool.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
#include "paddle/phi/core/enforce.h"
|
||||
#include "paddle/phi/core/tensor_utils.h"
|
||||
#include "paddle/phi/kernels/funcs/math_function.h"
|
||||
|
||||
TEST(selected_rows_functor, gpu_add) {
|
||||
phi::GPUPlace gpu_place(0);
|
||||
phi::CPUPlace cpu_place;
|
||||
phi::GPUContext& ctx = *reinterpret_cast<phi::GPUContext*>(
|
||||
phi::DeviceContextPool::Instance().Get(gpu_place));
|
||||
phi::funcs::SetConstant<phi::GPUContext, float> functor;
|
||||
int64_t height = 10;
|
||||
int64_t row_numel = 10;
|
||||
|
||||
std::vector<int64_t> rows1{0, 4, 7};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows1{
|
||||
new phi::SelectedRows(rows1, height)};
|
||||
auto* in1_value = selected_rows1->mutable_value();
|
||||
in1_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows1.size()), row_numel}),
|
||||
gpu_place);
|
||||
functor(ctx, in1_value, 1.0);
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
PADDLE_ENFORCE_EQ(hipDeviceSynchronize(),
|
||||
0,
|
||||
common::errors::PreconditionNotMet(
|
||||
"The all synchronization on the cuda is error!"));
|
||||
#else
|
||||
PADDLE_ENFORCE_EQ(cudaDeviceSynchronize(),
|
||||
0,
|
||||
common::errors::PreconditionNotMet(
|
||||
"The all synchronization on the cuda is error!"));
|
||||
#endif
|
||||
|
||||
std::vector<int64_t> rows2{0, 5, 7, 9};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows2{
|
||||
new phi::SelectedRows(rows2, height)};
|
||||
auto* in2_value = selected_rows2->mutable_value();
|
||||
in2_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows2.size()), row_numel}),
|
||||
gpu_place);
|
||||
functor(ctx, in2_value, 2.0);
|
||||
|
||||
std::unique_ptr<phi::SelectedRows> output{new phi::SelectedRows()};
|
||||
auto* out_value = output->mutable_value();
|
||||
|
||||
// simply concat two SelectedRows
|
||||
out_value->mutable_data<float>(common::make_ddim({7, 10}), gpu_place);
|
||||
|
||||
phi::funcs::SelectedRowsAdd<phi::GPUContext, float> add_functor;
|
||||
add_functor(ctx, *selected_rows1, *selected_rows2, output.get());
|
||||
|
||||
auto out_height = output->height();
|
||||
EXPECT_EQ(out_height, height);
|
||||
|
||||
auto& out_rows = output->rows();
|
||||
|
||||
// input1 rows
|
||||
EXPECT_EQ(out_rows[0], 0);
|
||||
EXPECT_EQ(out_rows[1], 4);
|
||||
EXPECT_EQ(out_rows[2], 7);
|
||||
// input2 rows
|
||||
EXPECT_EQ(out_rows[3], 0);
|
||||
EXPECT_EQ(out_rows[4], 5);
|
||||
EXPECT_EQ(out_rows[5], 7);
|
||||
EXPECT_EQ(out_rows[6], 9);
|
||||
|
||||
phi::DenseTensor out_cpu;
|
||||
phi::Copy(ctx, *out_value, cpu_place, true, &out_cpu);
|
||||
|
||||
auto* out_cpu_data = out_cpu.data<float>();
|
||||
// input1 value
|
||||
EXPECT_EQ(out_cpu_data[0 * row_numel + 0], 1.0);
|
||||
EXPECT_EQ(out_cpu_data[0 * row_numel + 8], 1.0);
|
||||
EXPECT_EQ(out_cpu_data[1 * row_numel + 1], 1.0);
|
||||
EXPECT_EQ(out_cpu_data[2 * row_numel + 6], 1.0);
|
||||
// input2 value
|
||||
EXPECT_EQ(out_cpu_data[3 * row_numel + 3], 2.0);
|
||||
EXPECT_EQ(out_cpu_data[3 * row_numel + 8], 2.0);
|
||||
EXPECT_EQ(out_cpu_data[4 * row_numel + 4], 2.0);
|
||||
EXPECT_EQ(out_cpu_data[5 * row_numel + 7], 2.0);
|
||||
EXPECT_EQ(out_cpu_data[6 * row_numel + 9], 2.0);
|
||||
|
||||
std::unique_ptr<phi::DenseTensor> tensor1{new phi::DenseTensor()};
|
||||
tensor1->mutable_data<float>(common::make_ddim({height, row_numel}),
|
||||
gpu_place);
|
||||
functor(ctx, tensor1.get(), 3.0);
|
||||
|
||||
std::unique_ptr<phi::DenseTensor> tensor2{new phi::DenseTensor()};
|
||||
tensor2->mutable_data<float>(common::make_ddim({height, row_numel}),
|
||||
gpu_place);
|
||||
|
||||
phi::funcs::SelectedRowsAddTensor<phi::GPUContext, float> add_tensor_functor;
|
||||
add_tensor_functor(ctx, *output, *tensor1, tensor2.get());
|
||||
|
||||
phi::DenseTensor tensor2_cpu;
|
||||
phi::Copy(ctx, *tensor2, cpu_place, true, &tensor2_cpu);
|
||||
|
||||
auto* tensor2_cpu_data = tensor2_cpu.data<float>();
|
||||
// row0: 1.0 + 2.0 + 3.0
|
||||
EXPECT_EQ(tensor2_cpu_data[0 * row_numel + 0], 6.0);
|
||||
// row1: 3.0
|
||||
EXPECT_EQ(tensor2_cpu_data[1 * row_numel + 1], 3.0);
|
||||
// row4 : 1.0 + 3.0
|
||||
EXPECT_EQ(tensor2_cpu_data[4 * row_numel + 6], 4.0);
|
||||
// row5: 2.0 + 3.0
|
||||
EXPECT_EQ(tensor2_cpu_data[5 * row_numel + 7], 5.0);
|
||||
// row6: 3.0
|
||||
EXPECT_EQ(tensor2_cpu_data[6 * row_numel + 1], 3.0);
|
||||
// row7: 1.0 + 2.0 + 3.0
|
||||
EXPECT_EQ(tensor2_cpu_data[7 * row_numel + 3], 6.0);
|
||||
// row9: 2.0 + 3.0
|
||||
EXPECT_EQ(tensor2_cpu_data[9 * row_numel + 6], 5.0);
|
||||
}
|
||||
|
||||
TEST(selected_rows_functor, gpu_add_to) {
|
||||
phi::GPUPlace gpu_place(0);
|
||||
phi::CPUPlace cpu_place;
|
||||
phi::GPUContext& ctx = *reinterpret_cast<phi::GPUContext*>(
|
||||
phi::DeviceContextPool::Instance().Get(gpu_place));
|
||||
phi::funcs::SetConstant<phi::GPUContext, float> functor;
|
||||
int64_t height = 10;
|
||||
int64_t row_numel = 10;
|
||||
|
||||
std::vector<int64_t> rows1{0, 4, 7};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows1{
|
||||
new phi::SelectedRows(rows1, height)};
|
||||
auto* in1_value = selected_rows1->mutable_value();
|
||||
in1_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows1.size()), row_numel}),
|
||||
gpu_place);
|
||||
functor(ctx, in1_value, 1.0);
|
||||
|
||||
std::vector<int64_t> rows2{0, 5, 7, 9};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows2{
|
||||
new phi::SelectedRows(rows2, height)};
|
||||
auto* in2_value = selected_rows2->mutable_value();
|
||||
in2_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows2.size()), row_numel}),
|
||||
gpu_place);
|
||||
functor(ctx, in2_value, 2.0);
|
||||
|
||||
std::unique_ptr<phi::SelectedRows> output{new phi::SelectedRows()};
|
||||
output->set_height(height);
|
||||
auto* out_value = output->mutable_value();
|
||||
|
||||
// simply concat two SelectedRows
|
||||
out_value->mutable_data<float>(common::make_ddim({7, 10}), gpu_place);
|
||||
|
||||
phi::funcs::SelectedRowsAddTo<phi::GPUContext, float> add_to_functor;
|
||||
add_to_functor(ctx, *selected_rows1, 0, output.get());
|
||||
add_to_functor(ctx, *selected_rows2, in1_value->numel(), output.get());
|
||||
|
||||
auto out_height = output->height();
|
||||
EXPECT_EQ(out_height, height);
|
||||
|
||||
auto& out_rows = output->rows();
|
||||
|
||||
// input1 rows
|
||||
EXPECT_EQ(out_rows[0], 0);
|
||||
EXPECT_EQ(out_rows[1], 4);
|
||||
EXPECT_EQ(out_rows[2], 7);
|
||||
// input2 rows
|
||||
EXPECT_EQ(out_rows[3], 0);
|
||||
EXPECT_EQ(out_rows[4], 5);
|
||||
EXPECT_EQ(out_rows[5], 7);
|
||||
EXPECT_EQ(out_rows[6], 9);
|
||||
|
||||
phi::DenseTensor out_cpu;
|
||||
phi::Copy(ctx, *out_value, cpu_place, true, &out_cpu);
|
||||
|
||||
auto* out_cpu_data = out_cpu.data<float>();
|
||||
// input1 value
|
||||
EXPECT_EQ(out_cpu_data[0 * row_numel + 0], 1.0);
|
||||
EXPECT_EQ(out_cpu_data[0 * row_numel + 8], 1.0);
|
||||
EXPECT_EQ(out_cpu_data[1 * row_numel + 1], 1.0);
|
||||
EXPECT_EQ(out_cpu_data[2 * row_numel + 6], 1.0);
|
||||
// input2 value
|
||||
EXPECT_EQ(out_cpu_data[3 * row_numel + 3], 2.0);
|
||||
EXPECT_EQ(out_cpu_data[3 * row_numel + 8], 2.0);
|
||||
EXPECT_EQ(out_cpu_data[4 * row_numel + 4], 2.0);
|
||||
EXPECT_EQ(out_cpu_data[5 * row_numel + 7], 2.0);
|
||||
EXPECT_EQ(out_cpu_data[6 * row_numel + 9], 2.0);
|
||||
|
||||
std::unique_ptr<phi::DenseTensor> tensor1{new phi::DenseTensor()};
|
||||
tensor1->mutable_data<float>(common::make_ddim({height, row_numel}),
|
||||
gpu_place);
|
||||
functor(ctx, tensor1.get(), 3.0);
|
||||
|
||||
phi::funcs::SelectedRowsAddToTensor<phi::GPUContext, float>
|
||||
add_to_tensor_functor;
|
||||
add_to_tensor_functor(ctx, *output, tensor1.get());
|
||||
|
||||
phi::DenseTensor tensor1_cpu;
|
||||
phi::Copy(ctx, *tensor1, cpu_place, true, &tensor1_cpu);
|
||||
|
||||
auto* tensor1_cpu_data = tensor1_cpu.data<float>();
|
||||
// row0: 1.0 + 2.0 + 3.0
|
||||
EXPECT_EQ(tensor1_cpu_data[0 * row_numel + 0], 6.0);
|
||||
// row1: 3.0
|
||||
EXPECT_EQ(tensor1_cpu_data[1 * row_numel + 1], 3.0);
|
||||
// row4 : 1.0 + 3.0
|
||||
EXPECT_EQ(tensor1_cpu_data[4 * row_numel + 6], 4.0);
|
||||
// row5: 2.0 + 3.0
|
||||
EXPECT_EQ(tensor1_cpu_data[5 * row_numel + 7], 5.0);
|
||||
// row6: 3.0
|
||||
EXPECT_EQ(tensor1_cpu_data[6 * row_numel + 1], 3.0);
|
||||
// row7: 1.0 + 2.0 + 3.0
|
||||
EXPECT_EQ(tensor1_cpu_data[7 * row_numel + 3], 6.0);
|
||||
// row9: 2.0 + 3.0
|
||||
EXPECT_EQ(tensor1_cpu_data[9 * row_numel + 6], 5.0);
|
||||
}
|
||||
|
||||
TEST(selected_rows_functor, gpu_merge_add) {
|
||||
phi::GPUPlace gpu_place(0);
|
||||
phi::CPUPlace cpu_place;
|
||||
phi::GPUContext& ctx = *reinterpret_cast<phi::GPUContext*>(
|
||||
phi::DeviceContextPool::Instance().Get(gpu_place));
|
||||
phi::funcs::SetConstant<phi::GPUContext, float> set_const;
|
||||
|
||||
int64_t height = 10;
|
||||
int64_t row_numel = 8;
|
||||
|
||||
std::vector<int64_t> rows1{5, 2, 5, 3, 5};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows1{
|
||||
new phi::SelectedRows(rows1, height)};
|
||||
auto* in1_value = selected_rows1->mutable_value();
|
||||
in1_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows1.size()), row_numel}),
|
||||
gpu_place);
|
||||
set_const(ctx, in1_value, 1.0);
|
||||
|
||||
std::vector<int64_t> rows2{2, 5, 3, 5, 3};
|
||||
std::unique_ptr<phi::SelectedRows> selected_rows2{
|
||||
new phi::SelectedRows(rows2, height)};
|
||||
auto* in2_value = selected_rows2->mutable_value();
|
||||
in2_value->mutable_data<float>(
|
||||
common::make_ddim({static_cast<int64_t>(rows2.size()), row_numel}),
|
||||
gpu_place);
|
||||
set_const(ctx, in2_value, 1.0);
|
||||
|
||||
std::unique_ptr<phi::SelectedRows> output{new phi::SelectedRows()};
|
||||
output->set_height(height);
|
||||
phi::funcs::scatter::MergeAdd<phi::GPUContext, float> merge_add_functor;
|
||||
|
||||
std::vector<const phi::SelectedRows*> inputs;
|
||||
inputs.push_back(selected_rows1.get());
|
||||
inputs.push_back(selected_rows2.get());
|
||||
merge_add_functor(ctx, inputs, output.get());
|
||||
|
||||
phi::DenseTensor output_cpu;
|
||||
phi::Copy(ctx, output->value(), cpu_place, true, &output_cpu);
|
||||
|
||||
EXPECT_EQ(output->height(), height);
|
||||
EXPECT_EQ(output->value().dims(), common::make_ddim({3, row_numel}));
|
||||
|
||||
std::vector<int64_t> ret_rows{2, 3, 5};
|
||||
EXPECT_EQ(output->rows(), ret_rows);
|
||||
|
||||
auto* out_data = output_cpu.data<float>();
|
||||
for (size_t i = 0; i < ret_rows.size(); ++i) {
|
||||
for (size_t j = 0; j < static_cast<size_t>(row_numel); ++j) {
|
||||
EXPECT_EQ(out_data[i * row_numel + j], ret_rows[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
/* Copyright (c) 2022 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 "paddle/phi/kernels/funcs/vol2col.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <array>
|
||||
|
||||
#include "paddle/fluid/framework/tensor_util.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
#include "paddle/phi/core/platform/device_context.h"
|
||||
|
||||
template <typename DeviceContext, typename Place>
|
||||
void testVol2col() {
|
||||
phi::DenseTensor input;
|
||||
phi::DenseTensor input_tmp;
|
||||
phi::DenseTensor output;
|
||||
phi::DenseTensor output_tmp;
|
||||
|
||||
auto* place = new Place();
|
||||
DeviceContext* context = new DeviceContext(*place);
|
||||
/**
|
||||
* input = [[0, 1, 2,
|
||||
* 3, 4, 5]
|
||||
* [6, 7, 8,
|
||||
* 9, 10, 11]]
|
||||
*
|
||||
* output = [0, 1
|
||||
* 1, 2
|
||||
* 3, 4
|
||||
* 4, 5
|
||||
* 6, 7
|
||||
* 7, 8
|
||||
* 9, 10
|
||||
* 10, 11]
|
||||
*
|
||||
* col2vol = [[0, 2, 2,
|
||||
* 3, 8, 5]
|
||||
* [6, 14, 8,
|
||||
* 9, 20, 11]]
|
||||
*
|
||||
*/
|
||||
int input_depth = 2;
|
||||
int input_height = 2;
|
||||
int input_width = 3;
|
||||
int filter_size = 2;
|
||||
std::vector<int> strides({1, 1, 1});
|
||||
std::vector<int> paddings({0, 0, 0});
|
||||
std::vector<int> dilations({1, 1, 1});
|
||||
int output_depth =
|
||||
(input_depth - filter_size + 2 * paddings[0]) / strides[0] + 1;
|
||||
int output_height =
|
||||
(input_height - filter_size + 2 * paddings[1]) / strides[1] + 1;
|
||||
int output_width =
|
||||
(input_width - filter_size + 2 * paddings[2]) / strides[2] + 1;
|
||||
|
||||
// Vol2Col test
|
||||
float* input_ptr = input_tmp.mutable_data<float>(
|
||||
{1, input_depth, input_height, input_width}, phi::CPUPlace());
|
||||
std::array<float, 12> arr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
memcpy(input_ptr, arr.data(), 12 * sizeof(float));
|
||||
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
input = input_tmp;
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(input_tmp, *place, &input);
|
||||
}
|
||||
output.mutable_data<float>({1,
|
||||
filter_size,
|
||||
filter_size,
|
||||
filter_size,
|
||||
output_depth,
|
||||
output_height,
|
||||
output_width},
|
||||
*place);
|
||||
|
||||
phi::funcs::Vol2ColFunctor<DeviceContext, float> vol2col;
|
||||
vol2col(*context, input, dilations, strides, paddings, &output);
|
||||
|
||||
std::array<float, 16> vol_2_col = {
|
||||
0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11};
|
||||
float* out_cfo_ptr = nullptr;
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
out_cfo_ptr = output.data<float>();
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(output, phi::CPUPlace(), &output_tmp);
|
||||
out_cfo_ptr = output_tmp.data<float>();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
EXPECT_EQ(out_cfo_ptr[i], vol_2_col[i]);
|
||||
}
|
||||
|
||||
// Col2Vol test
|
||||
std::array<float, 12> col_2_vol = {0, 2, 2, 3, 8, 5, 6, 14, 8, 9, 20, 11};
|
||||
memset(input_ptr, 0, 12 * sizeof(float));
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
input = input_tmp;
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(input_tmp, *place, &input);
|
||||
}
|
||||
|
||||
phi::funcs::Col2VolFunctor<DeviceContext, float> col2vol;
|
||||
col2vol(*context, output, dilations, strides, paddings, &input);
|
||||
|
||||
float* in_ptr = nullptr;
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
in_ptr = input.data<float>();
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(input, phi::CPUPlace(), &input_tmp);
|
||||
in_ptr = input_tmp.data<float>();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 12; ++i) {
|
||||
EXPECT_EQ(in_ptr[i], col_2_vol[i]);
|
||||
}
|
||||
|
||||
delete place;
|
||||
delete context;
|
||||
}
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
template <>
|
||||
void testVol2col<phi::GPUContext, phi::GPUPlace>() {
|
||||
phi::DenseTensor input;
|
||||
phi::DenseTensor input_tmp;
|
||||
phi::DenseTensor output;
|
||||
phi::DenseTensor output_tmp;
|
||||
|
||||
auto* place = new phi::GPUPlace();
|
||||
auto* context = new phi::GPUContext(*place);
|
||||
context->SetAllocator(paddle::memory::allocation::AllocatorFacade::Instance()
|
||||
.GetAllocator(*place, context->stream())
|
||||
.get());
|
||||
context->PartialInitWithAllocator();
|
||||
|
||||
/**
|
||||
* input = [[0, 1, 2,
|
||||
* 3, 4, 5]
|
||||
* [6, 7, 8,
|
||||
* 9, 10, 11]]
|
||||
*
|
||||
* output = [0, 1
|
||||
* 1, 2
|
||||
* 3, 4
|
||||
* 4, 5
|
||||
* 6, 7
|
||||
* 7, 8
|
||||
* 9, 10
|
||||
* 10, 11]
|
||||
*
|
||||
* col2vol = [[0, 2, 2,
|
||||
* 3, 8, 5]
|
||||
* [6, 14, 8,
|
||||
* 9, 20, 11]]
|
||||
*
|
||||
*/
|
||||
int input_depth = 2;
|
||||
int input_height = 2;
|
||||
int input_width = 3;
|
||||
int filter_size = 2;
|
||||
std::vector<int> strides({1, 1, 1});
|
||||
std::vector<int> paddings({0, 0, 0});
|
||||
std::vector<int> dilations({1, 1, 1});
|
||||
int output_depth =
|
||||
(input_depth - filter_size + 2 * paddings[0]) / strides[0] + 1;
|
||||
int output_height =
|
||||
(input_height - filter_size + 2 * paddings[1]) / strides[1] + 1;
|
||||
int output_width =
|
||||
(input_width - filter_size + 2 * paddings[2]) / strides[2] + 1;
|
||||
|
||||
// Vol2Col test
|
||||
float* input_ptr = input_tmp.mutable_data<float>(
|
||||
{1, input_depth, input_height, input_width}, phi::CPUPlace());
|
||||
std::array<float, 12> arr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
memcpy(input_ptr, arr.data(), 12 * sizeof(float));
|
||||
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
input = input_tmp;
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(input_tmp, *place, &input);
|
||||
}
|
||||
output.mutable_data<float>({1,
|
||||
filter_size,
|
||||
filter_size,
|
||||
filter_size,
|
||||
output_depth,
|
||||
output_height,
|
||||
output_width},
|
||||
*place);
|
||||
|
||||
phi::funcs::Vol2ColFunctor<phi::GPUContext, float> vol2col;
|
||||
vol2col(*context, input, dilations, strides, paddings, &output);
|
||||
|
||||
std::array<float, 16> vol_2_col = {
|
||||
0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11};
|
||||
float* out_cfo_ptr;
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
out_cfo_ptr = output.data<float>();
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(output, phi::CPUPlace(), &output_tmp);
|
||||
out_cfo_ptr = output_tmp.data<float>();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
EXPECT_EQ(out_cfo_ptr[i], vol_2_col[i]);
|
||||
}
|
||||
|
||||
// Col2Vol test
|
||||
std::array<float, 12> col_2_vol = {0, 2, 2, 3, 8, 5, 6, 14, 8, 9, 20, 11};
|
||||
memset(input_ptr, 0, 12 * sizeof(float));
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
input = input_tmp;
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(input_tmp, *place, &input);
|
||||
}
|
||||
|
||||
phi::funcs::Col2VolFunctor<phi::GPUContext, float> col2vol;
|
||||
col2vol(*context, output, dilations, strides, paddings, &input);
|
||||
|
||||
float* in_ptr;
|
||||
if (phi::is_cpu_place(*place)) {
|
||||
in_ptr = input.data<float>();
|
||||
} else {
|
||||
paddle::framework::TensorCopySync(input, phi::CPUPlace(), &input_tmp);
|
||||
in_ptr = input_tmp.data<float>();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 12; ++i) {
|
||||
EXPECT_EQ(in_ptr[i], col_2_vol[i]);
|
||||
}
|
||||
|
||||
delete place;
|
||||
delete context;
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(math, vol2col) {
|
||||
testVol2col<phi::CPUContext, phi::CPUPlace>();
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
testVol2col<phi::GPUContext, phi::GPUPlace>();
|
||||
#endif // PADDLE_WITH_CUDA
|
||||
}
|
||||
Reference in New Issue
Block a user