chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:42 +08:00
commit e25996e7db
15472 changed files with 3536181 additions and 0 deletions
+136
View File
@@ -0,0 +1,136 @@
cc_test(
test_math_function
SRCS test_math_function.cc
DEPS phi common)
if(WITH_GPU)
nv_test(
test_math_function_gpu
SRCS test_math_function.cu
DEPS phi common)
nv_test(
test_broadcast_gpu
SRCS test_ternary_broadcast.cu
DEPS gtest)
endif()
if(WITH_ROCM)
hip_test(
test_math_function_gpu
SRCS test_math_function.cu
DEPS phi common)
endif()
cc_test(
test_cpu_vec
SRCS test_cpu_vec.cc
DEPS phi common)
# For String Kernels
if(WIN32)
cc_test(
test_strings_lower_upper_dev_api
SRCS test_strings_lower_upper_dev_api.cc
DEPS type_info common)
else()
cc_test(
test_strings_lower_upper_dev_api
SRCS test_strings_lower_upper_dev_api.cc
DEPS phi common)
endif()
if(WITH_GPU)
nv_test(
test_strings_lower_upper_dev_gpu_api
SRCS test_strings_lower_upper_dev_api.cu
DEPS phi common)
elseif(WITH_ROCM)
hip_test(
test_strings_lower_upper_dev_gpu_api
SRCS test_strings_lower_upper_dev_api.cu
DEPS phi common)
endif()
cc_test(
test_strings_copy_dev_api
SRCS test_strings_copy_dev_api.cc
DEPS phi common)
if(WITH_GPU)
nv_test(
test_strings_copy_dev_gpu_api
SRCS test_strings_copy_dev_api.cu
DEPS phi common)
elseif(WITH_ROCM)
hip_test(
test_strings_copy_dev_gpu_api
SRCS test_strings_copy_dev_api.cu
DEPS phi common)
endif()
if(WIN32)
cc_test(
test_memcpy_dev_api
SRCS test_memcpy_dev_api.cc
DEPS type_info common)
cc_test(
test_transfer_layout_dev_api
SRCS test_memcpy_dev_api.cc
DEPS type_info common)
else()
cc_test(
test_memcpy_dev_api
SRCS test_memcpy_dev_api.cc
DEPS phi common)
cc_test(
test_transfer_layout_dev_api
SRCS test_transfer_layout_dev_api.cc
DEPS phi common)
endif()
if(WITH_GPU)
nv_test(
test_gpu_timer
SRCS test_gpu_timer.cu
DEPS gtest)
nv_test(
test_auto_tune
SRCS test_auto_tune.cu
DEPS gtest)
cc_test(
test_fused_adam_kernel
SRCS test_fused_adam_kernel.cc
DEPS gtest phi common)
elseif(WITH_ROCM)
hip_test(
test_gpu_timer
SRCS test_gpu_timer.cu
DEPS gtest)
hip_test(
test_auto_tune
SRCS test_auto_tune.cu
DEPS gtest)
endif()
cc_test(
test_cache
SRCS test_cache.cc
DEPS gtest phi common)
cc_test(
strided_memcpy_test
SRCS strided_memcpy_test.cc
DEPS phi common)
if(WIN32)
cc_test(
sequence_padding_test
SRCS sequence_padding_test.cc
DEPS type_info common)
else()
cc_test(
sequence_padding_test
SRCS sequence_padding_test.cc
DEPS phi common)
endif()
cc_test(
sequence_pooling_test
SRCS sequence_pooling_test.cc
DEPS phi common)
@@ -0,0 +1,133 @@
/* Copyright (c) 2023 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/phi/kernels/funcs/sequence_padding.h"
#include "paddle/phi/backends/context_pool.h"
#include "paddle/phi/core/tensor_utils.h"
template <typename DeviceContext, typename T>
void TestSequencePadding(const DeviceContext &context,
const phi::LegacyLoD &lod,
const size_t sequence_width) {
phi::DenseTensor cpu_seq;
phi::DenseTensor cpu_seq_back;
phi::DenseTensor seq;
phi::DenseTensor seq_back;
phi::DenseTensor padding;
phi::DenseTensor cpu_pad_value;
phi::DenseTensor pad_value;
const size_t level = lod.size() - 1;
auto seq_dims = common::make_ddim({static_cast<int64_t>(lod[level].back()),
static_cast<int64_t>(sequence_width)});
cpu_seq.set_lod(lod);
auto *dev_ctx = static_cast<phi::CPUContext *>(
phi::DeviceContextPool::Instance().Get(phi::CPUPlace()));
cpu_seq.Resize(seq_dims);
dev_ctx->template Alloc<T>(&cpu_seq);
for (int64_t i = 0; i < cpu_seq.numel(); ++i) {
cpu_seq.data<T>()[i] = static_cast<T>(i);
}
auto place = context.GetPlace();
if (place.GetType() == phi::AllocationType::CPU) {
seq = cpu_seq;
} else {
phi::Copy(context, cpu_seq, place, true, &seq);
seq.set_lod(lod);
}
const size_t max_sequence_length =
phi::funcs::MaximumSequenceLength(lod[level]);
const size_t num_sequences = lod[level].size() - 1;
auto padding_dims =
common::make_ddim({static_cast<int64_t>(max_sequence_length),
static_cast<int64_t>(num_sequences),
static_cast<int64_t>(sequence_width)});
padding.Resize(padding_dims);
context.template Alloc<T>(&padding);
cpu_pad_value.Resize({1});
T *pad_value_data = dev_ctx->template Alloc<T>(&cpu_pad_value);
*pad_value_data = static_cast<T>(0);
if (place.GetType() == phi::AllocationType::CPU) {
pad_value = cpu_pad_value;
} else {
phi::Copy(context, cpu_pad_value, place, true, &pad_value);
}
phi::funcs::PaddingDenseTensorFunctor<DeviceContext, T>()(
context,
seq,
&padding,
pad_value,
-1,
0,
false,
phi::funcs::kLengthBatchWidth);
seq_back.set_lod(lod);
seq_back.Resize(seq_dims);
context.template Alloc<T>(&seq_back);
phi::funcs::UnpaddingDenseTensorFunctor<DeviceContext, T>()(
context, padding, &seq_back, -1, 0, false, phi::funcs::kLengthBatchWidth);
if (place.GetType() == phi::AllocationType::CPU) {
cpu_seq_back = seq_back;
} else {
phi::Copy(context, seq_back, phi::CPUPlace(), true, &cpu_seq_back);
cpu_seq_back.set_lod(lod);
}
EXPECT_EQ(cpu_seq.numel(), cpu_seq_back.numel());
EXPECT_EQ(cpu_seq.dims(), cpu_seq_back.dims());
for (int64_t i = 0; i < cpu_seq.numel(); ++i) {
EXPECT_EQ(cpu_seq.data<T>()[i], cpu_seq_back.data<T>()[i]);
}
}
TEST(Seq2BatchPadding, CPU) {
auto place = phi::CPUPlace();
auto *context = static_cast<phi::CPUContext *>(
phi::DeviceContextPool::Instance().Get(place));
phi::LegacyLoD lod1;
lod1.push_back(std::vector<size_t>{0, 10});
TestSequencePadding<phi::CPUContext, float>(*context, lod1, 16);
phi::LegacyLoD lod2;
lod2.push_back(std::vector<size_t>{0, 2, 7, 10});
TestSequencePadding<phi::CPUContext, float>(*context, lod2, 128);
}
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
TEST(SequencePadding, CUDA) {
auto place = phi::GPUPlace(0);
auto *context = static_cast<phi::GPUContext *>(
phi::DeviceContextPool::Instance().Get(place));
phi::LegacyLoD lod1;
lod1.push_back(std::vector<size_t>{0, 10});
TestSequencePadding<phi::GPUContext, float>(*context, lod1, 16);
phi::LegacyLoD lod2;
lod2.push_back(std::vector<size_t>{0, 2, 7, 10});
TestSequencePadding<phi::GPUContext, float>(*context, lod2, 128);
}
#endif
@@ -0,0 +1,148 @@
/* Copyright (c) 2023 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/phi/backends/context_pool.h"
#include "paddle/phi/common/place.h"
#include "paddle/phi/core/tensor_utils.h"
#include "paddle/phi/kernels/funcs/sequence_pooling.h"
template <typename DeviceContext, typename T>
void TestSequencePoolingSum(const DeviceContext &context,
const phi::LegacyLoD &lod,
const int64_t second_dim) {
phi::DenseTensor cpu_out_grad;
phi::DenseTensor cpu_in_grad;
phi::DenseTensor out_grad;
phi::DenseTensor in_grad;
// construct out_grad's tensor in cpu
const size_t out_first_dim = lod[0].size() - 1;
auto out_dims =
common::make_ddim({static_cast<int64_t>(out_first_dim), second_dim});
cpu_out_grad.mutable_data<T>(out_dims, phi::CPUPlace());
for (int64_t i = 0; i < cpu_out_grad.numel(); ++i) {
cpu_out_grad.data<T>()[i] = static_cast<T>(i);
}
// copy to dst out_grad
auto place = context.GetPlace();
if (place == phi::CPUPlace()) {
out_grad = cpu_out_grad;
} else {
phi::Copy(context, cpu_out_grad, place, true, &out_grad);
}
// construct in_grad
in_grad.set_lod(lod);
auto in_dims =
common::make_ddim({static_cast<int64_t>(lod[0].back()), second_dim});
in_grad.mutable_data<T>(in_dims, place);
// check tensor construction result
PADDLE_ENFORCE_EQ(
in_grad.dims().size(),
out_grad.dims().size(),
common::errors::InvalidArgument(
"The dimension of input and output shall be same. Expected %ld == "
"%ld, but got %ld != %ld. Please check the input value.",
in_grad.dims().size(),
out_grad.dims().size(),
in_grad.dims().size(),
out_grad.dims().size()));
for (int64_t i = 1; i < out_grad.dims().size(); ++i) {
PADDLE_ENFORCE_EQ(
in_grad.dims()[i],
out_grad.dims()[i],
common::errors::InvalidArgument(
"The dimension of input and output shall be same. Expected %ld == "
"%ld, but got %ld != %ld. Please check the input value.",
in_grad.dims()[i],
out_grad.dims()[i],
in_grad.dims()[i],
out_grad.dims()[i]));
}
// call functor
phi::funcs::SequencePoolGradFunctor<DeviceContext, T>()(
context, "SUM", out_grad, &in_grad);
if (place == phi::CPUPlace()) {
cpu_in_grad = in_grad;
} else {
phi::Copy(context, in_grad, phi::CPUPlace(), true, &cpu_in_grad);
cpu_in_grad.set_lod(in_grad.lod());
}
EXPECT_EQ(in_grad.numel(), static_cast<int64_t>(lod[0].back() * second_dim));
EXPECT_EQ(in_grad.lod(), lod);
if (place == phi::CPUPlace()) {
for (size_t i = 0; i < in_grad.lod()[0].size() - 1; ++i) {
int64_t begin = static_cast<int64_t>(in_grad.lod()[0][i]);
int64_t end = static_cast<int64_t>(in_grad.lod()[0][i + 1]);
phi::DenseTensor tmp = in_grad.Slice(begin, end);
for (int64_t j = 0; j != tmp.numel() / second_dim; ++j) {
for (int64_t m = 0; m != second_dim; ++m) {
EXPECT_EQ(tmp.data<T>()[m + j * second_dim],
out_grad.data<T>()[m + i * second_dim]);
}
}
}
} else {
for (size_t i = 0; i < cpu_in_grad.lod()[0].size() - 1; ++i) {
int64_t begin = static_cast<int64_t>(cpu_in_grad.lod()[0][i]);
int64_t end = static_cast<int64_t>(cpu_in_grad.lod()[0][i + 1]);
phi::DenseTensor tmp = cpu_in_grad.Slice(begin, end);
for (int64_t j = 0; j != tmp.numel() / second_dim; ++j) {
for (int64_t m = 0; m != second_dim; ++m) {
EXPECT_EQ(tmp.data<T>()[m + j * second_dim],
cpu_out_grad.data<T>()[m + i * second_dim]);
}
}
}
}
}
TEST(SequencePoolingGrad, CPU_SUM) {
auto place = phi::CPUPlace();
auto *context = static_cast<phi::CPUContext *>(
phi::DeviceContextPool::Instance().Get(place));
phi::LegacyLoD lod1;
lod1.push_back(std::vector<size_t>{0, 10});
TestSequencePoolingSum<phi::CPUContext, float>(*context, lod1, 128);
phi::LegacyLoD lod2;
lod2.push_back(std::vector<size_t>{0, 2, 7, 10});
TestSequencePoolingSum<phi::CPUContext, float>(*context, lod2, 128);
}
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
TEST(SequencePoolingGrad, CUDA_SUM) {
auto place = phi::GPUPlace(0);
auto *context = static_cast<phi::GPUContext *>(
phi::DeviceContextPool::Instance().Get(place));
phi::LegacyLoD lod1;
lod1.push_back(std::vector<size_t>{0, 10});
TestSequencePoolingSum<phi::GPUContext, float>(*context, lod1, 128);
phi::LegacyLoD lod2;
lod2.push_back(std::vector<size_t>{0, 2, 7, 10});
TestSequencePoolingSum<phi::GPUContext, float>(*context, lod2, 128);
}
#endif
+172
View File
@@ -0,0 +1,172 @@
/* Copyright (c) 2023 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/strided_memcpy.h"
#include <array>
#include "gtest/gtest.h"
#include "paddle/phi/backends/context_pool.h"
#include "paddle/phi/common/memory_utils.h"
namespace phi {
namespace tests {
TEST(StridedMemcpy, CPUCrop) {
// clang-format off
int src[] = {// NOLINT
0, 1, 2, 0, 0,
0, 3, 4, 0, 0,
0, 0, 0, 0, 0,
};
// clang-format on
phi::DDim src_stride({5, 1});
std::array<int, 4> dst = {};
phi::DDim dst_dim({2, 2});
phi::DDim dst_stride({2, 1});
phi::CPUContext ctx;
phi::funcs::StridedMemcpy<int>(
ctx, src + 1, src_stride, dst_dim, dst_stride, dst.data());
ASSERT_EQ(1, dst[0]);
ASSERT_EQ(2, dst[1]);
ASSERT_EQ(3, dst[2]);
ASSERT_EQ(4, dst[3]);
}
TEST(StridedMemcpy, CPUConcat) {
// clang-format off
int src[] = { // NOLINT
1, 2,
3, 4
};
// clang-format on
std::array<int, 8> dst = {};
phi::DDim src_stride({2, 1});
phi::DDim dst_dim({2, 2});
phi::DDim dst_stride({4, 1});
phi::CPUContext ctx;
phi::funcs::StridedMemcpy<int>(
ctx, src, src_stride, dst_dim, dst_stride, dst.data());
phi::funcs::StridedMemcpy<int>(
ctx, src, src_stride, dst_dim, dst_stride, dst.data() + 2);
// clang-format off
int expect_dst[] = { // NOLINT
1, 2, 1, 2,
3, 4, 3, 4
};
// clang-format on
for (size_t i = 0; i < sizeof(expect_dst) / sizeof(int); ++i) {
ASSERT_EQ(expect_dst[i], dst[i]);
}
}
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
TEST(StridedMemcpy, GPUCrop) {
// clang-format off
std::array<int, 15> src = {
0, 1, 2, 0, 0,
0, 3, 4, 0, 0,
0, 0, 0, 0, 0,
};
// clang-format on
phi::GPUPlace gpu0(0);
phi::CPUPlace cpu;
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* ctx = reinterpret_cast<phi::GPUContext*>(pool.Get(phi::GPUPlace()));
auto src_allocation = phi::memory_utils::Alloc(gpu0, sizeof(src));
int* gpu_src = reinterpret_cast<int*>(src_allocation->ptr());
memory_utils::Copy(
gpu0, gpu_src, cpu, src.data(), sizeof(src), ctx->stream());
phi::DDim src_stride({5, 1});
std::array<int, 4> dst = {};
auto dst_allocation = phi::memory_utils::Alloc(gpu0, sizeof(dst));
int* gpu_dst = reinterpret_cast<int*>(dst_allocation->ptr());
phi::DDim dst_dim({2, 2});
phi::DDim dst_stride({2, 1});
phi::funcs::StridedMemcpy<int>(
*ctx, gpu_src + 1, src_stride, dst_dim, dst_stride, gpu_dst);
memory_utils::Copy(
cpu, dst.data(), gpu0, gpu_dst, sizeof(dst), ctx->stream());
ctx->Wait();
ASSERT_EQ(1, dst[0]);
ASSERT_EQ(2, dst[1]);
ASSERT_EQ(3, dst[2]);
ASSERT_EQ(4, dst[3]);
}
TEST(StridedMemcpy, GPUConcat) {
// clang-format off
std::array<int, 4> src = {
1, 2,
3, 4
};
// clang-format on
phi::GPUPlace gpu0(0);
phi::CPUPlace cpu;
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* ctx = reinterpret_cast<phi::GPUContext*>(pool.Get(phi::GPUPlace()));
auto gpu_src_allocation = phi::memory_utils::Alloc(gpu0, sizeof(src));
int* gpu_src = reinterpret_cast<int*>(gpu_src_allocation->ptr());
memory_utils::Copy(
gpu0, gpu_src, cpu, src.data(), sizeof(src), ctx->stream());
std::array<int, 8> dst = {};
auto gpu_dst_allocation = phi::memory_utils::Alloc(gpu0, sizeof(dst));
int* gpu_dst = reinterpret_cast<int*>(gpu_dst_allocation->ptr());
phi::DDim src_stride({2, 1});
phi::DDim dst_dim({2, 2});
phi::DDim dst_stride({4, 1});
phi::funcs::StridedMemcpy<int>(
*ctx, gpu_src, src_stride, dst_dim, dst_stride, gpu_dst);
phi::funcs::StridedMemcpy<int>(
*ctx, gpu_src, src_stride, dst_dim, dst_stride, gpu_dst + 2);
memory_utils::Copy(
cpu, dst.data(), gpu0, gpu_dst, sizeof(dst), ctx->stream());
ctx->Wait();
// clang-format off
std::array<int, 8> expect_dst = {
1, 2, 1, 2,
3, 4, 3, 4
};
// clang-format on
for (size_t i = 0; i < sizeof(expect_dst) / sizeof(int); ++i) {
ASSERT_EQ(expect_dst[i], dst[i]);
}
}
#endif
} // namespace tests
} // namespace phi
+137
View File
@@ -0,0 +1,137 @@
// 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 <gtest/gtest.h>
#include "glog/logging.h"
#include "paddle/phi/api/lib/utils/allocator.h"
#include "paddle/phi/backends/context_pool.h"
#include "paddle/phi/backends/gpu/gpu_launch_config.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/tensor_meta.h"
#include "paddle/phi/core/tensor_utils.h"
#include "paddle/phi/kernels/autotune/auto_tune_base.h"
#include "paddle/phi/kernels/funcs/aligned_vector.h"
namespace tune = phi::autotune;
template <typename T, int VecSize>
__global__ void VecSumTest(const T* x, T* y, int N) {
#ifdef __HIPCC__
int idx = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
#else
int idx = blockDim.x * blockIdx.x + threadIdx.x;
#endif
using LoadT = phi::AlignedVector<T, VecSize>;
for (int i = idx * VecSize; i < N; i += blockDim.x * gridDim.x * VecSize) {
LoadT x_vec;
LoadT y_vec;
phi::Load<T, VecSize>(&x[i], &x_vec);
phi::Load<T, VecSize>(&y[i], &y_vec);
#pragma unroll
for (int j = 0; j < VecSize; j++) {
y_vec[j] = x_vec[j] + y_vec[j];
}
phi::Store<T, VecSize>(y_vec, &y[i]);
}
}
template <int Vecsize>
float Algo(const phi::GPUContext& ctx,
const phi::DenseTensor& d_in,
phi::DenseTensor* d_out,
size_t N,
size_t threads,
size_t blocks) {
const float* d_in_data = d_in.data<float>();
float* d_out_data = d_out->data<float>();
#ifdef __HIPCC__
hipLaunchKernelGGL(HIP_KERNEL_NAME(VecSumTest<float, Vecsize>),
dim3(blocks),
dim3(threads),
0,
0,
d_in_data,
d_out_data,
N);
#else
VLOG(3) << "Vecsize is " << Vecsize;
VecSumTest<float, Vecsize>
<<<blocks, threads, 0, ctx.stream()>>>(d_in_data, d_out_data, N);
#endif
return Vecsize;
}
TEST(AutoTune, sum) {
int64_t N = 1 << 20;
size_t blocks = 512;
size_t threads = 256;
size_t size = sizeof(float) * N;
const auto alloc_cpu =
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace());
auto in1 = std::make_shared<phi::DenseTensor>(
alloc_cpu.get(),
phi::DenseTensorMeta(phi::DataType::FLOAT32,
common::make_ddim({N}),
phi::DataLayout::NCHW));
auto in2 = std::make_shared<phi::DenseTensor>(
alloc_cpu.get(),
phi::DenseTensorMeta(phi::DataType::FLOAT32,
common::make_ddim({N}),
phi::DataLayout::NCHW));
float* in1_data = in1->data<float>();
float* in2_data = in2->data<float>();
for (size_t i = 0; i < N; i++) {
in1_data[i] = 1.0f;
in2_data[i] = 2.0f;
}
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
const auto alloc_cuda =
std::make_unique<paddle::experimental::DefaultAllocator>(phi::GPUPlace());
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto place = phi::GPUPlace();
auto* dev_ctx = static_cast<const phi::GPUContext*>(pool.GetByPlace(place));
auto stream = dev_ctx->stream();
auto d_in1 = std::make_shared<phi::DenseTensor>(
alloc_cuda.get(),
phi::DenseTensorMeta(phi::DataType::FLOAT32,
common::make_ddim({N}),
phi::DataLayout::NCHW));
auto d_in2 = std::make_shared<phi::DenseTensor>(
alloc_cuda.get(),
phi::DenseTensorMeta(phi::DataType::FLOAT32,
common::make_ddim({N}),
phi::DataLayout::NCHW));
phi::Copy(*dev_ctx, *in1.get(), phi::GPUPlace(), false, d_in1.get());
phi::Copy(*dev_ctx, *in2.get(), phi::GPUPlace(), false, d_in2.get());
// 1. Test call_back.
VLOG(3) << ">>> [CallBack]: Test case.";
auto callback1 = tune::MakeCallback<float>(Algo<4>);
auto callback2 = tune::MakeCallback<float>(Algo<2>);
auto callback3 = tune::MakeCallback<float>(Algo<1>);
std::vector<decltype(callback1)> callbacks{callback1, callback2, callback3};
for (int i = 0; i < callbacks.size(); ++i) {
dev_ctx->Wait();
phi::GpuTimer timer;
timer.Start(0);
callbacks[i].Run(*dev_ctx, *d_in1.get(), d_in2.get(), N, threads, blocks);
timer.Stop(0);
VLOG(3) << "kernel[" << i << "]: time cost is " << timer.ElapsedTime();
}
#endif
}
+68
View File
@@ -0,0 +1,68 @@
// 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 <gtest/gtest.h>
#include <cmath>
#include <functional>
#include "paddle/phi/kernels/autotune/cache.h"
#include "glog/logging.h"
enum ConvAlgos { GEMMKernel = 0, CuDNNKernel_1 = 1, CuDNNKernel_2 = 2 };
TEST(AlgosCache, AlgosCache) {
auto autotune_cache = phi::autotune::AutoTuneCache::Instance();
auto& cache =
autotune_cache.GetConv(phi::autotune::AlgorithmType::kConvForward);
std::vector<int64_t> x_shape = {4, 224, 224, 3};
std::vector<int64_t> w_shape = {32, 3, 3, 3};
std::vector<int> paddings = {0, 0};
std::vector<int> strides = {2, 2};
std::vector<int> dilations = {1, 1};
phi::DataType dtype = phi::CppTypeToDataType<float>::Type();
phi::autotune::ConvCacheKey key(
x_shape, w_shape, paddings, strides, dilations, dtype, 0, 0);
EXPECT_EQ(cache.Find(key), false);
phi::autotune::ConvAutoTuneResult node(
static_cast<int64_t>(ConvAlgos::GEMMKernel), 0, false);
cache.Set(key, node);
EXPECT_EQ(cache.Size(), 1);
EXPECT_EQ(cache.Find(key), true);
auto algo = cache.Get(key);
EXPECT_EQ(algo.algo, ConvAlgos::GEMMKernel);
x_shape = {4, 128, 128, 3};
phi::autotune::ConvCacheKey key1(
x_shape, w_shape, paddings, strides, dilations, dtype, 0, 1);
EXPECT_EQ(cache.Find(key1), false);
phi::autotune::ConvAutoTuneResult node1(
static_cast<int64_t>(ConvAlgos::CuDNNKernel_1), 0, false);
cache.Set(key1, node1);
EXPECT_EQ(cache.Size(), 2);
EXPECT_EQ(cache.CacheHits(), 1);
EXPECT_EQ(cache.CacheMisses(), 2);
float cache_hit_rate = static_cast<float>(1) / static_cast<float>(3);
EXPECT_LT(std::abs(cache_hit_rate - cache.CacheHitRate()), 1e-5);
autotune_cache.UpdateStatus();
EXPECT_EQ(autotune_cache.Size(), 2);
EXPECT_EQ(autotune_cache.CacheHits(), 1);
EXPECT_EQ(autotune_cache.CacheMisses(), 2);
EXPECT_LT(std::abs(cache_hit_rate - autotune_cache.CacheHitRate()), 1e-5);
}
+346
View File
@@ -0,0 +1,346 @@
/* 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 <cmath>
#include <cstring>
#include <random>
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/phi/common/port.h"
#include "paddle/phi/kernels/funcs/cpu_vec.h"
namespace phi {
namespace tests {
inline double GetCurrentUS() {
struct timeval time = {};
gettimeofday(&time, nullptr);
return 1e+6 * time.tv_sec + time.tv_usec; // NOLINT
}
constexpr int repeat = 1000;
template <typename T>
inline T _sigmoid(T x) {
const T min = SIGMOID_THRESHOLD_MIN;
const T max = SIGMOID_THRESHOLD_MAX;
T tmp = (x < min) ? min : ((x > max) ? max : x);
return static_cast<T>(1) / (static_cast<T>(1) + std::exp(-tmp));
}
template <typename T>
inline T _tanh(T x) {
return static_cast<T>(2) * _sigmoid<T>(static_cast<T>(2) * x) -
static_cast<T>(1);
}
template <typename T>
void ref_sigmoid(const int n, const T* x, T* y) {
for (int i = 0; i < n; ++i) {
y[i] = _sigmoid(x[i]);
}
}
template <typename T>
void ref_tanh(const int n, const T* x, T* y) {
for (int i = 0; i < n; ++i) {
y[i] = _tanh(x[i]);
}
}
template <typename T>
void ref_relu(const int n, const T* x, T* y) {
for (int i = 0; i < n; ++i) {
y[i] = x[i] > 0 ? x[i] : 0;
}
}
template <typename T>
void RandomVec(const int n,
T* a,
const T lower = static_cast<T>(-20.f),
const T upper = static_cast<T>(20.f)) {
static unsigned int seed = 100;
std::mt19937 rng(seed++);
std::uniform_real_distribution<double> uniform_dist(0, 1);
for (int i = 0; i < n; ++i) {
a[i] = static_cast<T>(uniform_dist(rng) * (upper - lower) + lower);
}
}
template <typename T>
void TestAndBench(const int n,
std::function<void(const int, const T*, T*)> tgt,
std::function<void(const int, const T*, T*)> ref) {
std::vector<T> x(n);
std::vector<T> ytgt(n), yref(n);
RandomVec<T>(n, x.data());
const T* x_data = x.data();
T* ytgt_data = ytgt.data();
T* yref_data = yref.data();
auto st = GetCurrentUS();
for (int i = 0; i < repeat; ++i) {
tgt(n, x_data, ytgt_data);
}
auto mt = GetCurrentUS();
for (int i = 0; i < repeat; ++i) {
ref(n, x_data, yref_data);
}
auto et = GetCurrentUS();
VLOG(3) << "Vec size " << n << ": refer takes: " << (et - mt) / repeat
<< " us, tgt takes: " << (mt - st) / repeat;
for (int i = 0; i < n; ++i) {
EXPECT_NEAR(ytgt_data[i], yref_data[i], 1e-3);
}
}
TEST(CpuVecTest, sigmoid) {
using namespace phi::funcs; // NOLINT
for (auto sz : {1, 2, 15, 16, 30, 32, 128, 200, 512}) {
TestAndBench<float>(sz, vec_sigmoid<float>, ref_sigmoid<float>);
TestAndBench<float>(
sz, vec_sigmoid<float, backends::cpu::avx>, ref_sigmoid<float>);
TestAndBench<float>(
sz, vec_sigmoid<float, backends::cpu::avx2>, ref_sigmoid<float>);
TestAndBench<float>(
sz, vec_sigmoid<float, backends::cpu::avx512f>, ref_sigmoid<float>);
}
TestAndBench<double>(30, vec_sigmoid<double>, ref_sigmoid<double>);
}
TEST(CpuVecTest, tanh) {
using namespace phi::funcs; // NOLINT
for (auto sz : {1, 2, 15, 16, 30, 32, 128, 200, 512}) {
TestAndBench<float>(sz, vec_tanh<float>, ref_tanh<float>);
TestAndBench<float>(
sz, vec_tanh<float, backends::cpu::avx>, ref_tanh<float>);
TestAndBench<float>(
sz, vec_tanh<float, backends::cpu::avx2>, ref_tanh<float>);
TestAndBench<float>(
sz, vec_tanh<float, backends::cpu::avx512f>, ref_tanh<float>);
}
TestAndBench<double>(30, vec_tanh<double>, ref_tanh<double>);
}
TEST(CpuVecTest, relu) {
using namespace phi::funcs; // NOLINT
for (auto sz : {1, 2, 15, 16, 30, 32, 128, 200, 512}) {
TestAndBench<float>(sz, vec_relu<float>, ref_relu<float>);
TestAndBench<float>(
sz, vec_relu<float, backends::cpu::avx>, ref_relu<float>);
TestAndBench<float>(
sz, vec_relu<float, backends::cpu::avx2>, ref_relu<float>);
TestAndBench<float>(
sz, vec_relu<float, backends::cpu::avx512f>, ref_relu<float>);
}
TestAndBench<double>(30, vec_relu<double>, ref_relu<double>);
}
template <typename T>
void compare_sum(size_t n,
std::function<void(const size_t, const T*, T*)> tgt,
std::function<void(const size_t, const T*, T*)> ref) {
std::vector<T> x(n);
T ytgt_data, yref_data;
RandomVec<T>(n, x.data(), static_cast<T>(-2), static_cast<T>(2));
const T* x_data = x.data();
tgt(n, x_data, &ytgt_data);
ref(n, x_data, &yref_data);
EXPECT_NEAR(ytgt_data, yref_data, 1e-3);
}
TEST(CpuVecTest, vec_sum) {
using namespace phi::funcs; // NOLINT
for (size_t sz : {1, 2, 15, 16, 30, 32, 128, 200, 512}) {
compare_sum<float>(
sz, vec_sum<float>, vec_sum<float, backends::cpu::isa_any>);
compare_sum<float>(sz,
vec_sum<float, backends::cpu::avx>,
vec_sum<float, backends::cpu::isa_any>);
}
compare_sum<double>(
30U, vec_sum<double>, vec_sum<double, backends::cpu::isa_any>);
}
template <typename T>
void compare_clip(
size_t n,
T threshold,
std::function<void(const size_t, const T, const T*, T*)> tgt,
std::function<void(const size_t, const T, const T*, T*)> ref) {
std::vector<T> x(n);
std::vector<T> ytgt(n), yref(n);
RandomVec<T>(n, x.data(), static_cast<T>(-2), static_cast<T>(2));
const T* x_data = x.data();
T* yref_data = yref.data();
T* ytgt_data = ytgt.data();
tgt(n, threshold, x_data, ytgt_data);
ref(n, threshold, x_data, yref_data);
for (size_t i = 0; i < n; ++i) {
EXPECT_NEAR(ytgt_data[i], yref_data[i], 1e-3);
}
}
TEST(CpuVecTest, vec_clip) {
using namespace phi::funcs; // NOLINT
for (size_t sz : {1, 2, 15, 16, 30, 32, 128, 200, 512}) {
compare_clip<float>(
sz, -4.f, vec_clip<float>, vec_clip<float, backends::cpu::isa_any>);
compare_clip<float>(sz,
-1.1f,
vec_clip<float, backends::cpu::avx>,
vec_clip<float, backends::cpu::isa_any>);
}
compare_clip<double>(
30U, 1.0, vec_clip<double>, vec_clip<double, backends::cpu::isa_any>);
}
template <typename T>
void compare_mul(
size_t n,
std::function<void(const size_t, const T*, const T*, T*)> tgt,
std::function<void(const size_t, const T*, const T*, T*)> ref) {
std::vector<T> x(n), y(n);
std::vector<T> ztgt(n), zref(n);
RandomVec<T>(n, x.data(), static_cast<T>(-2), static_cast<T>(2));
RandomVec<T>(n, y.data(), static_cast<T>(-2), static_cast<T>(2));
const T* x_data = x.data();
const T* y_data = y.data();
T* ztgt_data = ztgt.data();
T* zref_data = zref.data();
tgt(n, x_data, y_data, ztgt_data);
ref(n, x_data, y_data, zref_data);
for (size_t i = 0; i < n; ++i) {
EXPECT_NEAR(ztgt_data[i], zref_data[i], 1e-3);
}
}
TEST(CpuVecTest, vec_mul) {
using namespace phi::funcs; // NOLINT
for (size_t sz : {1, 2, 15, 16, 30, 32, 128, 200, 512}) {
compare_mul<float>(
sz, vec_mul<float>, vec_mul<float, backends::cpu::isa_any>);
compare_mul<float>(sz,
vec_mul<float, backends::cpu::avx>,
vec_mul<float, backends::cpu::isa_any>);
}
compare_mul<double>(
30U, vec_mul<double>, vec_mul<double, backends::cpu::isa_any>);
}
template <typename T>
void compare_mul_reduce(
size_t n,
std::function<void(const size_t, const T*, const T*, T*)> tgt,
std::function<void(const size_t, const T*, const T*, T*)> ref) {
std::vector<T> x(n), y(n);
T ztgt_data, zref_data;
RandomVec<T>(n, x.data(), static_cast<T>(-2), static_cast<T>(2));
RandomVec<T>(n, y.data(), static_cast<T>(-2), static_cast<T>(2));
const T* x_data = x.data();
const T* y_data = y.data();
tgt(n, x_data, y_data, &ztgt_data);
ref(n, x_data, y_data, &zref_data);
EXPECT_NEAR(ztgt_data, zref_data, 1e-3);
}
TEST(CpuVecTest, vec_mul_reduce) {
using namespace phi::funcs; // NOLINT
for (size_t sz : {1, 2, 15, 16, 30, 32, 128, 200, 512}) {
compare_mul_reduce<float>(sz,
vec_mul_reduce<float>,
vec_mul_reduce<float, backends::cpu::isa_any>);
compare_mul_reduce<float>(sz,
vec_mul_reduce<float, backends::cpu::avx>,
vec_mul_reduce<float, backends::cpu::isa_any>);
}
compare_mul_reduce<double>(30U,
vec_mul_reduce<double>,
vec_mul_reduce<double, backends::cpu::isa_any>);
}
template <typename T>
void TestInplace(const int n,
std::function<void(const int, const T*, T*)> tgt,
std::function<void(const int, const T*, T*)> ref) {
std::vector<T> x(n);
std::vector<T> ytgt(n), yref(n);
RandomVec<T>(n, x.data());
const T* x_data = x.data();
T* yref_data = yref.data();
T* ytgt_data = ytgt.data();
std::memcpy(yref_data, x_data, sizeof(T) * n);
std::memcpy(ytgt_data, x_data, sizeof(T) * n);
ref(n, yref_data, yref_data);
tgt(n, ytgt_data, ytgt_data);
for (int i = 0; i < n; ++i) {
EXPECT_NEAR(ytgt_data[i], yref_data[i], 1e-3);
}
}
TEST(CpuVecTest, inplace_sigmoid) {
using namespace phi::funcs; // NOLINT
for (auto sz : {1, 2, 15, 16, 30, 32, 128, 200, 512}) {
TestInplace<float>(sz, vec_sigmoid<float>, ref_sigmoid<float>);
TestInplace<float>(
sz, vec_sigmoid<float, backends::cpu::avx>, ref_sigmoid<float>);
TestInplace<float>(
sz, vec_sigmoid<float, backends::cpu::avx2>, ref_sigmoid<float>);
TestInplace<float>(
sz, vec_sigmoid<float, backends::cpu::avx512f>, ref_sigmoid<float>);
}
TestInplace<double>(30, vec_sigmoid<double>, ref_sigmoid<double>);
}
TEST(CpuVecTest, inplace_tanh) {
using namespace phi::funcs; // NOLINT
for (auto sz : {1, 2, 15, 16, 30, 32, 128, 200, 512}) {
TestInplace<float>(sz, vec_tanh<float>, ref_tanh<float>);
TestInplace<float>(
sz, vec_tanh<float, backends::cpu::avx>, ref_tanh<float>);
TestInplace<float>(
sz, vec_tanh<float, backends::cpu::avx2>, ref_tanh<float>);
TestInplace<float>(
sz, vec_tanh<float, backends::cpu::avx512f>, ref_tanh<float>);
}
TestInplace<double>(30, vec_tanh<double>, ref_tanh<double>);
}
TEST(CpuVecTest, inplace_relu) {
using namespace phi::funcs; // NOLINT
for (auto sz : {1, 2, 15, 16, 30, 32, 128, 200, 512}) {
TestInplace<float>(sz, vec_relu<float>, ref_relu<float>);
TestInplace<float>(
sz, vec_relu<float, backends::cpu::avx>, ref_relu<float>);
TestInplace<float>(
sz, vec_relu<float, backends::cpu::avx2>, ref_relu<float>);
TestInplace<float>(
sz, vec_relu<float, backends::cpu::avx512f>, ref_relu<float>);
}
TestInplace<double>(30, vec_relu<double>, ref_relu<double>);
}
} // namespace tests
} // namespace phi
@@ -0,0 +1,524 @@
// Copyright (c) 2023 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 <vector>
#include "paddle/phi/backends/cpu/cpu_context.h"
#include "paddle/phi/core/generator.h"
#ifdef PADDLE_WITH_CUDA
#include "paddle/phi/backends/gpu/gpu_context.h"
#endif
#include "gtest/gtest.h"
#include "paddle/phi/backends/context_pool.h"
#include "paddle/phi/common/amp_type_traits.h"
#include "paddle/phi/core/tensor_utils.h"
#include "paddle/phi/infermeta/multiary.h"
#include "paddle/phi/kernels/abs_kernel.h"
#include "paddle/phi/kernels/adam_kernel.h"
#include "paddle/phi/kernels/adamw_kernel.h"
#include "paddle/phi/kernels/cast_kernel.h"
#include "paddle/phi/kernels/elementwise_subtract_kernel.h"
#include "paddle/phi/kernels/full_kernel.h"
#include "paddle/phi/kernels/fused_adam_kernel.h"
#include "paddle/phi/kernels/gaussian_kernel.h"
#include "paddle/phi/kernels/legacy/reduce_max_kernel.h"
namespace phi {
template <typename T, typename Context>
auto GenerateRandomTensorVectors(
const Context &ctx, const std::vector<std::vector<int64_t>> &shapes) {
size_t n = shapes.size();
std::vector<DenseTensor> tensors(n);
for (size_t i = 0; i < n; ++i) {
GaussianKernel<T, Context>(ctx,
shapes[i],
0.0f,
1.0f,
0,
phi::CppTypeToDataType<T>::Type(),
&tensors[i]);
}
return tensors;
}
template <typename T, typename Context>
auto GenerateConstantTensorVectors(
const Context &ctx,
const std::vector<std::vector<int64_t>> &shapes,
T value) {
size_t n = shapes.size();
std::vector<DenseTensor> tensors(n);
for (size_t i = 0; i < n; ++i) {
FullKernel<T, Context>(
ctx, shapes[i], value, phi::CppTypeToDataType<T>::Type(), &tensors[i]);
}
return tensors;
}
static auto ToConstTensorPtrVector(const std::vector<DenseTensor> &tensors) {
std::vector<const DenseTensor *> results;
results.reserve(tensors.size());
for (const auto &t : tensors) {
results.push_back(&t);
}
return results;
}
static auto ToMutableTensorPtrVector(
std::vector<DenseTensor> &tensors) { // NOLINT
std::vector<DenseTensor *> results;
results.reserve(tensors.size());
for (auto &t : tensors) {
results.push_back(&t);
}
return results;
}
static auto ToMetaTensorVector(const std::vector<DenseTensor> &tensors) {
std::vector<MetaTensor> results;
results.reserve(tensors.size());
for (auto &t : tensors) {
results.emplace_back(t);
}
return results;
}
static auto ToConstMetaTensorPtrVector(
const std::vector<MetaTensor> &meta_tensors) {
std::vector<const MetaTensor *> results;
results.reserve(meta_tensors.size());
for (auto &t : meta_tensors) {
results.push_back(&t);
}
return results;
}
static auto ToMutableMetaTensorPtrVector(
std::vector<MetaTensor> &meta_tensors) { // NOLINT
std::vector<MetaTensor *> results;
results.reserve(meta_tensors.size());
for (auto &t : meta_tensors) {
results.push_back(&t);
}
return results;
}
template <typename T, typename Context>
struct AdamInfo {
using AdamWScalarT = double;
const Context *ctx;
std::vector<std::vector<int64_t>> shapes;
std::vector<DenseTensor> params;
std::vector<DenseTensor> master_params;
std::vector<DenseTensor> moment1s;
std::vector<DenseTensor> moment2s;
std::vector<DenseTensor> moment2s_max;
std::vector<DenseTensor> beta1_pows;
std::vector<DenseTensor> beta2_pows;
DenseTensor learning_rate;
DenseTensor adamw_learning_rate;
float beta1;
float beta2;
float weight_decay;
float epsilon = 1e-6;
bool multi_precision;
bool use_adamw;
int chunk_size = 4096;
bool amsgrad;
using MT = typename phi::dtype::MPTypeTrait<T>::Type;
AdamInfo(const Context &ctx_ref,
const std::vector<std::vector<int64_t>> &shapes,
float beta1,
float beta2,
float weight_decay,
bool multi_precision,
bool use_adamw,
bool amsgrad)
: ctx(&ctx_ref),
shapes(shapes),
beta1(beta1),
beta2(beta2),
weight_decay(weight_decay),
multi_precision(multi_precision),
use_adamw(use_adamw),
amsgrad(amsgrad) {
std::vector<std::vector<int64_t>> one_shapes(shapes.size(),
std::vector<int64_t>(1, 1));
std::vector<std::vector<int64_t>> learning_rate_shapes(
one_shapes.begin(), one_shapes.begin() + 1);
params = GenerateRandomTensorVectors<T, Context>(*ctx, shapes);
learning_rate = GenerateConstantTensorVectors<double, Context>(
*ctx, learning_rate_shapes, 1e-3)[0];
adamw_learning_rate = GenerateConstantTensorVectors<AdamWScalarT, Context>(
*ctx, learning_rate_shapes, 1e-3)[0];
moment1s = GenerateConstantTensorVectors<MT, Context>(*ctx, shapes, 0);
moment2s = GenerateConstantTensorVectors<MT, Context>(*ctx, shapes, 0);
moment2s_max = GenerateConstantTensorVectors<MT, Context>(*ctx, shapes, 0);
if (multi_precision) {
master_params.resize(shapes.size());
for (size_t i = 0; i < shapes.size(); ++i) {
master_params[i] = Cast<T, Context>(
*ctx, params[i], phi::CppTypeToDataType<MT>::Type());
}
}
beta1_pows =
GenerateConstantTensorVectors<MT, Context>(*ctx, one_shapes, beta1);
beta2_pows =
GenerateConstantTensorVectors<MT, Context>(*ctx, one_shapes, beta2);
}
void Update(bool use_fused, const std::vector<DenseTensor> &grads) {
if (use_fused) {
UpdateWithFusedAdam(grads);
} else {
for (size_t j = 0; j < params.size(); ++j) {
if (use_adamw) {
UpdateWithAdamWBaseline(grads, j);
} else {
UpdateWithAdamBaseline(grads, j);
}
}
}
}
static AdamInfo<T, Context> DeepCopy(const AdamInfo &other) {
AdamInfo copied(*other.ctx,
other.shapes,
other.beta1,
other.beta2,
other.weight_decay,
other.multi_precision,
other.use_adamw,
other.amsgrad);
auto copy_tensor = [&other](const DenseTensor &x, DenseTensor *y) {
Copy<Context>(*other.ctx, x, x.place(), false, y);
};
auto copy_tensors = [&other](const std::vector<DenseTensor> &xs,
std::vector<DenseTensor> *ys) {
for (size_t i = 0; i < xs.size(); ++i) {
Copy<Context>(*other.ctx, xs[i], xs[i].place(), false, &((*ys)[i]));
}
};
copy_tensors(other.params, &copied.params);
copy_tensors(other.master_params, &copied.master_params);
copy_tensors(other.moment1s, &copied.moment1s);
copy_tensors(other.moment2s, &copied.moment2s);
copy_tensors(other.moment2s_max, &copied.moment2s_max);
copy_tensors(other.beta1_pows, &copied.beta1_pows);
copy_tensors(other.beta2_pows, &copied.beta2_pows);
copy_tensor(other.learning_rate, &copied.learning_rate);
copy_tensor(other.adamw_learning_rate, &copied.adamw_learning_rate);
copied.epsilon = other.epsilon;
copied.chunk_size = other.chunk_size;
other.ctx->Wait();
return copied;
}
private:
void UpdateWithFusedAdam(const std::vector<DenseTensor> &grads) {
auto param_metas = ToMetaTensorVector(params);
auto grad_metas = ToMetaTensorVector(grads);
auto master_param_metas = ToMetaTensorVector(master_params);
auto moment1_metas = ToMetaTensorVector(moment1s);
auto moment2_metas = ToMetaTensorVector(moment2s);
auto moment2_max_metas = ToMetaTensorVector(moment2s_max);
auto beta1_pow_metas = ToMetaTensorVector(beta1_pows);
auto beta2_pow_metas = ToMetaTensorVector(beta2_pows);
FusedAdamInferMeta(ToConstMetaTensorPtrVector(param_metas),
ToConstMetaTensorPtrVector(grad_metas),
adamw_learning_rate,
ToConstMetaTensorPtrVector(moment1_metas),
ToConstMetaTensorPtrVector(moment2_metas),
ToConstMetaTensorPtrVector(moment2_max_metas),
ToConstMetaTensorPtrVector(beta1_pow_metas),
ToConstMetaTensorPtrVector(beta2_pow_metas),
multi_precision
? paddle::make_optional(
ToConstMetaTensorPtrVector(master_param_metas))
: paddle::none,
MetaTensor(),
beta1,
beta2,
epsilon,
chunk_size,
weight_decay,
use_adamw,
multi_precision,
false,
amsgrad,
ToMutableMetaTensorPtrVector(param_metas),
ToMutableMetaTensorPtrVector(moment1_metas),
ToMutableMetaTensorPtrVector(moment2_metas),
ToMutableMetaTensorPtrVector(moment2_max_metas),
ToMutableMetaTensorPtrVector(beta1_pow_metas),
ToMutableMetaTensorPtrVector(beta2_pow_metas),
ToMutableMetaTensorPtrVector(master_param_metas));
FusedAdamKernel<T, Context>(
*ctx,
ToConstTensorPtrVector(params),
ToConstTensorPtrVector(grads),
adamw_learning_rate,
ToConstTensorPtrVector(moment1s),
ToConstTensorPtrVector(moment2s),
ToConstTensorPtrVector(moment2s_max),
ToConstTensorPtrVector(beta1_pows),
ToConstTensorPtrVector(beta2_pows),
multi_precision
? paddle::make_optional(ToConstTensorPtrVector(master_params))
: paddle::none,
paddle::none,
beta1,
beta2,
epsilon,
chunk_size,
weight_decay,
use_adamw,
multi_precision,
false,
amsgrad,
ToMutableTensorPtrVector(params),
ToMutableTensorPtrVector(moment1s),
ToMutableTensorPtrVector(moment2s),
ToMutableTensorPtrVector(moment2s_max),
ToMutableTensorPtrVector(beta1_pows),
ToMutableTensorPtrVector(beta2_pows),
ToMutableTensorPtrVector(master_params));
}
void UpdateWithAdamWBaseline(const std::vector<DenseTensor> &grads,
size_t idx) {
AdamwDenseKernel<T, Context>(
*ctx,
params[idx],
grads[idx],
adamw_learning_rate,
moment1s[idx],
moment2s[idx],
moment2s_max[idx],
beta1_pows[idx],
beta2_pows[idx],
multi_precision ? paddle::make_optional(master_params[idx])
: paddle::none,
paddle::none,
beta1,
beta2,
epsilon,
1.0,
weight_decay,
true,
false,
1000,
multi_precision,
false,
amsgrad,
&params[idx],
&moment1s[idx],
&moment2s[idx],
&moment2s_max[idx],
&beta1_pows[idx],
&beta2_pows[idx],
multi_precision ? &master_params[idx] : nullptr);
}
void UpdateWithAdamBaseline(const std::vector<DenseTensor> &grads,
size_t idx) {
AdamDenseKernel<T, Context>(
*ctx,
params[idx],
grads[idx],
learning_rate,
moment1s[idx],
moment2s[idx],
moment2s_max[idx],
beta1_pows[idx],
beta2_pows[idx],
multi_precision ? paddle::make_optional(master_params[idx])
: paddle::none,
paddle::none,
beta1,
beta2,
epsilon,
false,
1000,
multi_precision,
false,
amsgrad,
&params[idx],
&moment1s[idx],
&moment2s[idx],
&moment2s_max[idx],
&beta1_pows[idx],
&beta2_pows[idx],
multi_precision ? &master_params[idx] : nullptr);
}
};
template <typename T, typename Context>
auto MaxDiff(const Context &ctx,
const DenseTensor &x_t,
const DenseTensor &y_t) {
using MT = typename AdamInfo<T, Context>::MT;
auto mp_dtype = phi::CppTypeToDataType<MT>::Type();
auto x = Cast<T, Context>(ctx, x_t, mp_dtype);
auto y = Cast<T, Context>(ctx, y_t, mp_dtype);
EXPECT_EQ(x.dims(), y.dims());
DenseTensor diff, diff_reduced, diff_reduced_cpu;
diff.Resize(x.dims());
ctx.template Alloc<MT>(&diff);
SubtractKernel<MT, Context>(ctx, x, y, &diff);
AbsKernel<MT, Context>(ctx, diff, &diff);
diff_reduced.Resize({1});
ctx.template Alloc<MT>(&diff_reduced);
MaxRawKernel<MT, Context>(ctx,
diff,
common::vectorize<int64_t>(x.dims()),
false,
true,
&diff_reduced);
diff_reduced_cpu.Resize(diff_reduced.dims());
ctx.template HostAlloc<MT>(&diff_reduced_cpu);
Copy<Context>(ctx, diff_reduced, CPUPlace(), true, &diff_reduced_cpu);
EXPECT_EQ(diff_reduced_cpu.place(), CPUPlace());
return diff_reduced_cpu.data<MT>()[0];
}
template <typename T, typename Context>
auto MaxDiff(const Context &ctx,
const std::vector<DenseTensor> &xs,
const std::vector<DenseTensor> &ys) {
using MT = typename AdamInfo<T, Context>::MT;
MT diff = 0;
for (size_t i = 0; i < xs.size(); ++i) {
diff = std::max<MT>(diff, MaxDiff<T, Context>(ctx, xs[i], ys[i]));
}
return diff;
}
template <typename T, typename PlaceType>
void TestFusedAdamBase(const std::vector<std::vector<int64_t>> &shapes,
float atol,
bool use_adamw,
bool amsgrad,
bool multi_precision = false,
float beta1 = 0.9,
float beta2 = 0.99,
float weight_decay = 0.1,
size_t steps = 5,
uint64_t seed = 10) {
const auto &ctx = *phi::DeviceContextPool::Instance().GetByPlace(PlaceType());
using Context = typename std::remove_const<
typename std::remove_pointer<decltype(&ctx)>::type>::type;
ctx.GetGenerator()->SetCurrentSeed(seed);
AdamInfo<T, Context> info1(ctx,
shapes,
beta1,
beta2,
weight_decay,
multi_precision,
use_adamw,
amsgrad);
auto info2 = AdamInfo<T, Context>::DeepCopy(info1);
for (size_t i = 0; i < steps; ++i) {
auto grads = GenerateRandomTensorVectors<T>(ctx, shapes);
info1.Update(false, grads);
info2.Update(true, grads);
}
using MT = typename decltype(info1)::MT;
#define PD_ADAM_TEST_COMP(__field, __dtype) \
do { \
MT __diff = MaxDiff<__dtype>(ctx, info1.__field, info2.__field); \
EXPECT_LE(__diff, static_cast<MT>(atol)) \
<< #__field << " has diff when use_adamw = " << use_adamw \
<< " , multi_precision = " << multi_precision; \
} while (0)
PD_ADAM_TEST_COMP(beta1_pows, MT);
PD_ADAM_TEST_COMP(beta2_pows, MT);
PD_ADAM_TEST_COMP(params, T);
PD_ADAM_TEST_COMP(master_params, MT);
PD_ADAM_TEST_COMP(moment1s, MT);
PD_ADAM_TEST_COMP(moment2s, MT);
PD_ADAM_TEST_COMP(moment2s_max, MT);
}
static auto GenerateRandomShapes(size_t n, uint64_t low, uint64_t high) {
std::random_device device;
std::default_random_engine engine(device());
std::uniform_int_distribution<uint64_t> dist(low, high);
std::vector<std::vector<int64_t>> shapes(n);
for (size_t i = 0; i < n; ++i) {
shapes[i].push_back(static_cast<int64_t>(dist(engine)));
}
return shapes;
}
TEST(fused_adam, test_fp32_cpu) {
auto shapes = GenerateRandomShapes(30, 10, 20);
float atol = 0.0f;
for (auto use_adamw : {false, true}) {
for (auto amsgrad : {false, true}) {
TestFusedAdamBase<float, CPUPlace>(shapes, atol, use_adamw, amsgrad);
}
}
}
#ifdef PADDLE_WITH_CUDA
TEST(fused_adam, test_fp32_gpu) {
auto shapes = GenerateRandomShapes(40, 0, 2 << 18);
for (auto use_adamw : {false, true}) {
// AdamwDenseKernel uses torch-compatible math (double-precision
// intermediates, FMA intrinsics) while FusedAdamKernel uses the
// original float-precision math, so allow a small tolerance for adamw.
float atol = use_adamw ? 1e-5f : 0.0f;
for (auto amsgrad : {false, true}) {
TestFusedAdamBase<float, GPUPlace>(shapes, atol, use_adamw, amsgrad);
}
}
}
TEST(fused_adam, test_fp16_gpu) {
auto shapes = GenerateRandomShapes(40, 0, 2 << 18);
float atol = 5e-3f;
for (auto use_adamw : {false, true}) {
for (auto amsgrad : {false, true}) {
TestFusedAdamBase<dtype::float16, GPUPlace>(
shapes, atol, use_adamw, amsgrad, true);
}
}
}
#endif
} // namespace phi
+119
View File
@@ -0,0 +1,119 @@
// 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 <gtest/gtest.h>
#include <functional>
#include "glog/logging.h"
#include "paddle/phi/kernels/autotune/gpu_timer.h"
#include "paddle/phi/kernels/funcs/aligned_vector.h"
template <typename T, int VecSize>
__global__ void VecSum(T *x, T *y, int N) {
#ifdef __HIPCC__
int idx = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
#else
int idx = blockDim.x * blockIdx.x + threadIdx.x;
#endif
using LoadT = phi::AlignedVector<T, VecSize>;
for (int i = idx * VecSize; i < N; i += blockDim.x * gridDim.x * VecSize) {
LoadT x_vec;
LoadT y_vec;
phi::Load<T, VecSize>(&x[i], &x_vec);
phi::Load<T, VecSize>(&y[i], &y_vec);
#pragma unroll
for (int j = 0; j < VecSize; j++) {
y_vec[j] = x_vec[j] + y_vec[j];
}
phi::Store<T, VecSize>(y_vec, &y[i]);
}
}
template <int Vecsize, int Threads, size_t Blocks>
void Algo(float *d_in, float *d_out, size_t N) {
#ifdef __HIPCC__
hipLaunchKernelGGL(HIP_KERNEL_NAME(VecSum<float, Vecsize>),
dim3(Blocks),
dim3(Threads),
0,
0,
d_in,
d_out,
N);
#else
VecSum<float, Vecsize><<<Blocks, Threads>>>(d_in, d_out, N);
#endif
}
TEST(GpuTimer, Sum) {
float *in1, *in2, *out;
float *d_in1, *d_in2;
size_t N = 1 << 20;
size_t size = sizeof(float) * N;
#ifdef __HIPCC__
hipMalloc(reinterpret_cast<void **>(&d_in1), size);
hipMalloc(reinterpret_cast<void **>(&d_in2), size);
#else
cudaMalloc(reinterpret_cast<void **>(&d_in1), size);
cudaMalloc(reinterpret_cast<void **>(&d_in2), size);
#endif
in1 = reinterpret_cast<float *>(malloc(size));
in2 = reinterpret_cast<float *>(malloc(size));
out = reinterpret_cast<float *>(malloc(size));
for (size_t i = 0; i < N; i++) {
in1[i] = 1.0f;
in2[i] = 2.0f;
}
#ifdef __HIPCC__
hipMemcpy(d_in1, in1, size, hipMemcpyHostToDevice);
hipMemcpy(d_in2, in2, size, hipMemcpyHostToDevice);
#else
cudaMemcpy(d_in1, in1, size, cudaMemcpyHostToDevice);
cudaMemcpy(d_in2, in2, size, cudaMemcpyHostToDevice);
#endif
using Functor = std::function<void(float *, float *, size_t)>;
Functor algo0 = Algo<4, 256, 1024>;
Functor algo1 = Algo<1, 256, 1024>;
Functor algo2 = Algo<1, 256, 8>;
std::vector<Functor> algos = {algo0, algo1, algo2};
for (int j = 0; j < algos.size(); ++j) {
auto algo = algos[j];
phi::GpuTimer timer;
timer.Start(0);
algo(d_in1, d_in2, N);
timer.Stop(0);
VLOG(3) << "algo: " << j << " cost: " << timer.ElapsedTime() << "ms";
}
#ifdef __HIPCC__
hipMemcpy(out, d_in2, size, hipMemcpyDeviceToHost);
#else
cudaMemcpy(out, d_in2, size, cudaMemcpyDeviceToHost);
#endif
free(in1);
free(in2);
free(out);
#ifdef __HIPCC__
hipFree(d_in1);
hipFree(d_in2);
#else
cudaFree(d_in1);
cudaFree(d_in2);
#endif
}
+380
View File
@@ -0,0 +1,380 @@
// 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 <array>
#include <set>
#include "gtest/gtest.h"
#include "paddle/phi/backends/context_pool.h"
#include "paddle/phi/kernels/funcs/blas/blas.h"
#include "paddle/phi/kernels/funcs/math_function.h"
namespace phi {
namespace tests {
template <typename T>
inline phi::funcs::BlasT<phi::CPUContext, T> GetBlas(
const phi::CPUContext& context) {
return phi::funcs::GetBlas<phi::CPUContext, T>(context);
}
TEST(math_function, gemm_notrans_cblas) {
phi::DenseTensor input1;
phi::DenseTensor input2;
phi::DenseTensor input3;
int m = 2;
int n = 3;
int k = 3;
auto* dev_ctx =
phi::DeviceContextPool::Instance().GetByPlace(phi::CPUPlace());
input1.Resize({2, 3});
float* input1_ptr = dev_ctx->template Alloc<float>(&input1);
std::array<float, 6> arr1 = {0, 1, 2, 3, 4, 5};
memcpy(input1_ptr, arr1.data(), 6 * sizeof(float));
input2.Resize({3, 4});
float* input2_ptr = dev_ctx->template Alloc<float>(&input2);
std::array<float, 12> arr2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
memcpy(input2_ptr, arr2.data(), 12 * sizeof(float));
input3.Resize({2, 4});
float* input3_ptr = dev_ctx->template Alloc<float>(&input3);
std::array<float, 8> arr3 = {0, 1, 2, 3, 4, 5, 6, 7};
memcpy(input3_ptr, arr3.data(), 8 * sizeof(float));
GetBlas<float>(*dev_ctx).GEMM(false,
false,
m,
n,
k,
1,
input1_ptr,
3,
input2_ptr + 1,
4,
1,
input3_ptr + 1,
4);
EXPECT_EQ(input3_ptr[0], 0);
EXPECT_EQ(input3_ptr[1], 24);
EXPECT_EQ(input3_ptr[2], 28);
EXPECT_EQ(input3_ptr[3], 32);
EXPECT_EQ(input3_ptr[4], 4);
EXPECT_EQ(input3_ptr[5], 73);
EXPECT_EQ(input3_ptr[6], 86);
EXPECT_EQ(input3_ptr[7], 99);
}
#ifdef PADDLE_WITH_LIBXSMM
template <typename T>
void MklSmmCompare(int m, int n, int k) {
phi::DenseTensor mat_a;
phi::DenseTensor mat_b;
phi::DenseTensor mat_c_smm;
phi::DenseTensor mat_c_mkl;
auto* dev_ctx =
phi::DeviceContextPool::Instance().GetByPlace(phi::CPUPlace());
mat_a.Resize({m, k});
T* A = dev_ctx->template Alloc<T>(&mat_a);
mat_b.Resize({k, n});
T* B = dev_ctx->template Alloc<T>(&mat_b);
mat_c_smm.Resize({m, n});
T* CSMM = dev_ctx->template Alloc<T>(&mat_c_smm);
mat_c_mkl.Resize({m, n});
T* CMKL = dev_ctx->template Alloc<T>(&mat_c_mkl);
T alpha = static_cast<T>(1);
T beta = static_cast<T>(0);
for (int i = 0; i < mat_a.numel(); ++i) {
A[i] = static_cast<T>(i);
}
for (int i = 0; i < mat_b.numel(); ++i) {
B[i] = static_cast<T>(i);
}
// lda,ldb,ldc follow RowMajor
int lda = k;
int ldb = n;
int ldc = n;
auto smm = [&, m, n, k, lda, ldb, ldc, alpha, beta]() {
const char transa = 'N';
const char transb = 'N';
phi::funcs::CBlas<T>::SMM_GEMM(&transa,
&transb,
&n,
&m,
&k,
&alpha,
B,
&ldb,
A,
&lda,
&beta,
CSMM,
&ldc);
};
auto mkl = [&, m, n, k, lda, ldb, ldc, alpha, beta]() {
phi::funcs::CBlas<T>::GEMM(CblasRowMajor,
CblasNoTrans,
CblasNoTrans,
m,
n,
k,
alpha,
A,
lda,
B,
ldb,
beta,
CMKL,
ldc);
};
smm();
mkl();
ASSERT_EQ(mat_c_mkl.numel(), mat_c_smm.numel());
for (int i = 0; i < mat_c_mkl.numel(); ++i) {
EXPECT_FLOAT_EQ(CSMM[i], CMKL[i]);
}
}
TEST(math_function, gemm_mkl_vs_smm) {
MklSmmCompare<float>(1, 2, 3);
MklSmmCompare<double>(1, 2, 3);
MklSmmCompare<float>(3, 2, 1);
MklSmmCompare<double>(3, 2, 1);
MklSmmCompare<float>(3, 8, 5);
MklSmmCompare<double>(3, 8, 5);
}
#endif
TEST(math_function, gemm_trans_cblas) {
phi::DenseTensor input1;
phi::DenseTensor input2;
phi::DenseTensor input3;
int m = 2;
int n = 3;
int k = 3;
auto* dev_ctx =
phi::DeviceContextPool::Instance().GetByPlace(phi::CPUPlace());
input1.Resize({2, 3});
float* input1_ptr = dev_ctx->template Alloc<float>(&input1);
std::array<float, 6> arr1 = {0, 1, 2, 3, 4, 5};
memcpy(input1_ptr, arr1.data(), 6 * sizeof(float));
input2.Resize({4, 3});
float* input2_ptr = dev_ctx->template Alloc<float>(&input2);
std::array<float, 12> arr2 = {0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11};
memcpy(input2_ptr, arr2.data(), 12 * sizeof(float));
input3.Resize({2, 4});
float* input3_ptr = dev_ctx->template Alloc<float>(&input3);
std::array<float, 8> arr3 = {0, 1, 2, 3, 4, 5, 6, 7};
memcpy(input3_ptr, arr3.data(), 8 * sizeof(float));
GetBlas<float>(*dev_ctx).GEMM(false,
true,
m,
n,
k,
1,
input1_ptr,
3,
input2_ptr + 3,
3,
1,
input3_ptr + 1,
4);
EXPECT_EQ(input3_ptr[0], 0);
EXPECT_EQ(input3_ptr[1], 24);
EXPECT_EQ(input3_ptr[2], 28);
EXPECT_EQ(input3_ptr[3], 32);
EXPECT_EQ(input3_ptr[4], 4);
EXPECT_EQ(input3_ptr[5], 73);
EXPECT_EQ(input3_ptr[6], 86);
EXPECT_EQ(input3_ptr[7], 99);
}
TEST(math_function, zero) {
phi::DenseTensor tensor;
auto* dev_ctx =
phi::DeviceContextPool::Instance().GetByPlace(phi::CPUPlace());
tensor.Resize({2, 2});
float* t = dev_ctx->template Alloc<float>(&tensor);
phi::funcs::SetConstant<phi::CPUContext, float> functor;
functor(*dev_ctx, &tensor, 0);
EXPECT_EQ(t[0], 0);
EXPECT_EQ(t[1], 0);
EXPECT_EQ(t[2], 0);
EXPECT_EQ(t[3], 0);
functor(*dev_ctx, &tensor, 1);
EXPECT_EQ(t[0], 1);
EXPECT_EQ(t[1], 1);
EXPECT_EQ(t[2], 1);
EXPECT_EQ(t[3], 1);
}
template <typename T>
void GemvTest(int m, int n, bool trans) {
phi::DenseTensor mat_a;
phi::DenseTensor vec_b;
phi::DenseTensor vec_c;
int b_num = trans ? m : n;
int c_num = trans ? n : m;
auto* dev_ctx =
phi::DeviceContextPool::Instance().GetByPlace(phi::CPUPlace());
mat_a.Resize({m, n});
T* data_a = dev_ctx->template Alloc<T>(&mat_a);
vec_b.Resize({b_num});
T* data_b = dev_ctx->template Alloc<T>(&vec_b);
vec_c.Resize({c_num});
T* data_c = dev_ctx->template Alloc<T>(&vec_c);
for (int i = 0; i < mat_a.numel(); ++i) {
data_a[i] = static_cast<T>(i);
}
for (int i = 0; i < vec_b.numel(); ++i) {
data_b[i] = static_cast<T>(i);
}
GetBlas<T>(*dev_ctx).GEMV(trans,
static_cast<int>(m),
static_cast<int>(n),
1.,
data_a,
data_b,
0.,
data_c);
if (!trans) {
for (int i = 0; i < m; ++i) {
T sum = 0.0;
for (int j = 0; j < n; ++j) {
sum += data_a[i * n + j] * data_b[j];
}
ASSERT_FLOAT_EQ(data_c[i], sum);
}
} else {
for (int i = 0; i < n; ++i) {
T sum = 0.0;
for (int j = 0; j < m; ++j) {
sum += data_a[j * n + i] * data_b[j];
}
ASSERT_FLOAT_EQ(data_c[i], sum);
}
}
}
TEST(math_function, gemv) {
GemvTest<float>(3, 13, false);
GemvTest<double>(4, 5, false);
GemvTest<float>(12, 7, true);
GemvTest<double>(7, 9, true);
}
TEST(math_function, set_constant) {
phi::DenseTensor t;
auto* dev_ctx =
phi::DeviceContextPool::Instance().GetByPlace(phi::CPUPlace());
t.Resize({10, 10});
dev_ctx->template Alloc<int>(&t);
phi::funcs::set_constant(*dev_ctx, &t, static_cast<int>(10));
for (int64_t i = 0; i < t.numel(); ++i) {
PADDLE_ENFORCE_EQ(10,
t.data<int>()[i],
common::errors::InvalidArgument(
"Each value of input tensor should be 10, "
"but received %d.",
t.data<int>()[i]));
}
}
template <typename T>
void GemmWarpTest(int m, int n, int k, T alpha, T beta) {
phi::DenseTensor mat_a;
phi::DenseTensor mat_b;
phi::DenseTensor mat_c_ref;
phi::DenseTensor mat_c_mkl;
auto* dev_ctx =
phi::DeviceContextPool::Instance().GetByPlace(phi::CPUPlace());
mat_a.Resize({m, k});
T* A = dev_ctx->template Alloc<T>(&mat_a);
mat_b.Resize({k, n});
T* B = dev_ctx->template Alloc<T>(&mat_b);
mat_c_ref.Resize({m, n});
T* CREF = dev_ctx->template Alloc<T>(&mat_c_ref);
mat_c_mkl.Resize({m, n});
T* CMKL = dev_ctx->template Alloc<T>(&mat_c_mkl);
ASSERT_EQ(mat_c_mkl.numel(), mat_c_ref.numel());
for (int i = 0; i < mat_a.numel(); ++i) {
A[i] = static_cast<T>(i);
}
for (int i = 0; i < mat_b.numel(); ++i) {
B[i] = static_cast<T>(i + 1);
}
for (int i = 0; i < mat_c_ref.numel(); ++i) {
CREF[i] = static_cast<T>(i + 2);
CMKL[i] = CREF[i];
}
// this would call gemm_warp
GetBlas<T>(*dev_ctx).GEMM(
CblasNoTrans, CblasNoTrans, m, n, k, alpha, A, B, beta, CREF);
// lda,ldb,ldc follow RowMajor
int lda = k;
int ldb = n;
int ldc = n;
phi::funcs::CBlas<T>::GEMM(CblasRowMajor,
CblasNoTrans,
CblasNoTrans,
m,
n,
k,
alpha,
A,
lda,
B,
ldb,
beta,
CMKL,
ldc);
for (int i = 0; i < mat_c_mkl.numel(); ++i) {
EXPECT_FLOAT_EQ(CREF[i], CMKL[i]);
}
}
TEST(math_function, gemm_warp) {
GemmWarpTest<float>(3, 2, 5, 1.f, 0.f);
GemmWarpTest<float>(3, 2, 5, 2.f, 1.f);
GemmWarpTest<float>(8, 5, 6, 1.f, 0.f);
GemmWarpTest<float>(8, 5, 6, 2.f, 1.f);
GemmWarpTest<double>(3, 2, 5, 1.0, 0.0);
GemmWarpTest<double>(3, 2, 5, 2.0, 1.0);
GemmWarpTest<double>(8, 5, 6, 1.0, 0.0);
GemmWarpTest<double>(8, 5, 6, 2.0, 1.0);
}
} // namespace tests
} // namespace phi
+527
View File
@@ -0,0 +1,527 @@
// 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/phi/backends/context_pool.h"
#include "paddle/phi/core/tensor_utils.h"
#include "paddle/phi/kernels/funcs/blas/blas.h"
#include "paddle/phi/kernels/funcs/math_function.h"
namespace phi {
namespace tests {
void fill_fp16_data(phi::dtype::float16* in_ptr,
size_t size,
const std::vector<float>& data) {
PADDLE_ENFORCE_EQ(
size,
data.size(),
common::errors::InvalidArgument(
"The size of argument data should"
" be equal to the argument size. Expected %d, but received %d.",
size,
data.size()));
for (size_t i = 0; i < data.size(); ++i) {
in_ptr[i] = phi::dtype::float16(data[i]);
}
}
template <typename T>
inline phi::funcs::BlasT<phi::GPUContext, T> GetBlas(
const phi::GPUContext& context) {
return phi::funcs::GetBlas<phi::GPUContext, T>(context);
}
TEST(math_function, notrans_mul_trans_fp32) {
phi::DenseTensor input1;
phi::DenseTensor input1_gpu;
phi::DenseTensor input2_gpu;
phi::DenseTensor out_gpu;
phi::DenseTensor out;
phi::CPUPlace cpu_place;
phi::GPUPlace gpu_place(0);
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* context = reinterpret_cast<phi::GPUContext*>(pool.Get(phi::GPUPlace()));
float* input1_ptr = input1.mutable_data<float>({2, 3}, cpu_place);
float arr[6] = {0, 1, 2, 3, 4, 5};
memcpy(input1_ptr, arr, 6 * sizeof(float));
phi::Copy(*context, input1, gpu_place, true, &input1_gpu);
phi::Copy(*context, input1, gpu_place, true, &input2_gpu);
out_gpu.mutable_data<float>({2, 2}, gpu_place);
GetBlas<float>(*context).MatMul(
input1_gpu, false, input2_gpu, true, 1, &out_gpu, 0);
phi::Copy(*context, out_gpu, cpu_place, true, &out);
float* out_ptr = out.data<float>();
context->Wait();
EXPECT_EQ(out_ptr[0], 5);
EXPECT_EQ(out_ptr[1], 14);
EXPECT_EQ(out_ptr[2], 14);
EXPECT_EQ(out_ptr[3], 50);
}
TEST(math_function, notrans_mul_trans_fp16) {
phi::DenseTensor input1;
phi::DenseTensor input1_gpu;
phi::DenseTensor input2_gpu;
phi::DenseTensor out_gpu;
phi::DenseTensor out;
phi::CPUPlace cpu_place;
phi::GPUPlace gpu_place(0);
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* context = reinterpret_cast<phi::GPUContext*>(pool.Get(phi::GPUPlace()));
// fp16 GEMM in cublas requires GPU compute capability >= 53
if (context->GetComputeCapability() < 53) {
return;
}
phi::dtype::float16* input1_ptr =
input1.mutable_data<phi::dtype::float16>({2, 3}, cpu_place);
fill_fp16_data(input1_ptr, input1.numel(), {0, 1, 2, 3, 4, 5});
phi::Copy(*context, input1, gpu_place, true, &input1_gpu);
phi::Copy(*context, input1, gpu_place, true, &input2_gpu);
out_gpu.mutable_data<phi::dtype::float16>({2, 2}, gpu_place);
GetBlas<phi::dtype::float16>(*context).MatMul(input1_gpu,
false,
input2_gpu,
true,
phi::dtype::float16(1),
&out_gpu,
phi::dtype::float16(0));
phi::Copy(*context, out_gpu, cpu_place, true, &out);
phi::dtype::float16* out_ptr = out.data<phi::dtype::float16>();
context->Wait();
EXPECT_EQ(static_cast<float>(out_ptr[0]), 5);
EXPECT_EQ(static_cast<float>(out_ptr[1]), 14);
EXPECT_EQ(static_cast<float>(out_ptr[2]), 14);
EXPECT_EQ(static_cast<float>(out_ptr[3]), 50);
}
TEST(math_function, trans_mul_notrans_fp32) {
phi::DenseTensor input1;
phi::DenseTensor input1_gpu;
phi::DenseTensor input2_gpu;
phi::DenseTensor out_gpu;
phi::DenseTensor out;
phi::CPUPlace cpu_place;
phi::GPUPlace gpu_place(0);
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* context = reinterpret_cast<phi::GPUContext*>(pool.Get(phi::GPUPlace()));
float* input1_ptr = input1.mutable_data<float>({2, 3}, cpu_place);
float arr[6] = {0, 1, 2, 3, 4, 5};
memcpy(input1_ptr, arr, 6 * sizeof(float));
phi::Copy(*context, input1, gpu_place, true, &input1_gpu);
phi::Copy(*context, input1, gpu_place, true, &input2_gpu);
out_gpu.mutable_data<float>({3, 3}, gpu_place);
GetBlas<float>(*context).MatMul(
input1_gpu, true, input2_gpu, false, 1, &out_gpu, 0);
phi::Copy(*context, out_gpu, cpu_place, true, &out);
float* out_ptr = out.data<float>();
context->Wait();
EXPECT_EQ(out_ptr[0], 9);
EXPECT_EQ(out_ptr[1], 12);
EXPECT_EQ(out_ptr[2], 15);
EXPECT_EQ(out_ptr[3], 12);
EXPECT_EQ(out_ptr[4], 17);
EXPECT_EQ(out_ptr[5], 22);
EXPECT_EQ(out_ptr[6], 15);
EXPECT_EQ(out_ptr[7], 22);
EXPECT_EQ(out_ptr[8], 29);
}
TEST(math_function, trans_mul_notrans_fp16) {
phi::DenseTensor input1;
phi::DenseTensor input1_gpu;
phi::DenseTensor input2_gpu;
phi::DenseTensor out_gpu;
phi::DenseTensor out;
phi::CPUPlace cpu_place;
phi::GPUPlace gpu_place(0);
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* context = reinterpret_cast<phi::GPUContext*>(pool.Get(phi::GPUPlace()));
// fp16 GEMM in cublas requires GPU compute capability >= 53
if (context->GetComputeCapability() < 53) {
return;
}
phi::dtype::float16* input1_ptr =
input1.mutable_data<phi::dtype::float16>({2, 3}, cpu_place);
fill_fp16_data(input1_ptr, input1.numel(), {0, 1, 2, 3, 4, 5});
phi::Copy(*context, input1, gpu_place, true, &input1_gpu);
phi::Copy(*context, input1, gpu_place, true, &input2_gpu);
out_gpu.mutable_data<phi::dtype::float16>({3, 3}, gpu_place);
GetBlas<phi::dtype::float16>(*context).MatMul(input1_gpu,
true,
input2_gpu,
false,
phi::dtype::float16(1),
&out_gpu,
phi::dtype::float16(0));
phi::Copy(*context, out_gpu, cpu_place, true, &out);
phi::dtype::float16* out_ptr = out.data<phi::dtype::float16>();
context->Wait();
EXPECT_EQ(static_cast<float>(out_ptr[0]), 9);
EXPECT_EQ(static_cast<float>(out_ptr[1]), 12);
EXPECT_EQ(static_cast<float>(out_ptr[2]), 15);
EXPECT_EQ(static_cast<float>(out_ptr[3]), 12);
EXPECT_EQ(static_cast<float>(out_ptr[4]), 17);
EXPECT_EQ(static_cast<float>(out_ptr[5]), 22);
EXPECT_EQ(static_cast<float>(out_ptr[6]), 15);
EXPECT_EQ(static_cast<float>(out_ptr[7]), 22);
EXPECT_EQ(static_cast<float>(out_ptr[8]), 29);
}
TEST(math_function, gemm_notrans_cublas_fp32) {
phi::DenseTensor input1;
phi::DenseTensor input2;
phi::DenseTensor input3;
phi::DenseTensor input1_gpu;
phi::DenseTensor input2_gpu;
phi::DenseTensor input3_gpu;
phi::CPUPlace cpu_place;
phi::GPUPlace gpu_place(0);
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* context = reinterpret_cast<phi::GPUContext*>(pool.Get(phi::GPUPlace()));
int m = 2;
int n = 3;
int k = 3;
float* input1_ptr = input1.mutable_data<float>({2, 3}, cpu_place);
float arr1[6] = {0, 1, 2, 3, 4, 5};
memcpy(input1_ptr, arr1, 6 * sizeof(float));
float* input2_ptr = input2.mutable_data<float>({3, 4}, cpu_place);
float arr2[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
memcpy(input2_ptr, arr2, 12 * sizeof(float));
float* input3_ptr = input3.mutable_data<float>({2, 4}, cpu_place);
float arr3[8] = {0, 1, 2, 3, 4, 5, 6, 7};
memcpy(input3_ptr, arr3, 8 * sizeof(float));
phi::Copy(*context, input1, gpu_place, true, &input1_gpu);
phi::Copy(*context, input2, gpu_place, true, &input2_gpu);
phi::Copy(*context, input3, gpu_place, true, &input3_gpu);
float* a = input1_gpu.data<float>();
float* b = input2_gpu.data<float>();
float* c = input3_gpu.mutable_data<float>(gpu_place);
GetBlas<float>(*context).GEMM(
false, false, m, n, k, 1, a, 3, b + 1, 4, 1, c + 1, 4);
phi::Copy(*context, input3_gpu, cpu_place, true, &input3);
// numpy code:
// a = np.arange(6).reshape(2, 3)
// b = np.arange(12).reshape(3, 4)[:, 1:]
// c = np.arange(8).reshape(2, 4)[:, 1:]
// out = np.arange(8).reshape(2, 4)
// out[:, 1:] = np.dot(a, b) + c
context->Wait();
EXPECT_EQ(input3_ptr[0], 0);
EXPECT_EQ(input3_ptr[1], 24);
EXPECT_EQ(input3_ptr[2], 28);
EXPECT_EQ(input3_ptr[3], 32);
EXPECT_EQ(input3_ptr[4], 4);
EXPECT_EQ(input3_ptr[5], 73);
EXPECT_EQ(input3_ptr[6], 86);
EXPECT_EQ(input3_ptr[7], 99);
}
TEST(math_function, gemm_notrans_cublas_fp16) {
phi::DenseTensor input1;
phi::DenseTensor input2;
phi::DenseTensor input3;
phi::DenseTensor input1_gpu;
phi::DenseTensor input2_gpu;
phi::DenseTensor input3_gpu;
phi::CPUPlace cpu_place;
phi::GPUPlace gpu_place(0);
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* context = reinterpret_cast<phi::GPUContext*>(pool.Get(phi::GPUPlace()));
// fp16 GEMM in cublas requires GPU compute capability >= 53
if (context->GetComputeCapability() < 53) {
return;
}
int m = 2;
int n = 3;
int k = 3;
phi::dtype::float16* input1_ptr =
input1.mutable_data<phi::dtype::float16>({2, 3}, cpu_place);
fill_fp16_data(input1_ptr, input1.numel(), {0, 1, 2, 3, 4, 5});
phi::dtype::float16* input2_ptr =
input2.mutable_data<phi::dtype::float16>({3, 4}, cpu_place);
fill_fp16_data(
input2_ptr, input2.numel(), {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11});
phi::dtype::float16* input3_ptr =
input3.mutable_data<phi::dtype::float16>({2, 4}, cpu_place);
fill_fp16_data(input3_ptr, input3.numel(), {0, 1, 2, 3, 4, 5, 6, 7});
phi::Copy(*context, input1, gpu_place, true, &input1_gpu);
phi::Copy(*context, input2, gpu_place, true, &input2_gpu);
phi::Copy(*context, input3, gpu_place, true, &input3_gpu);
phi::dtype::float16* a = input1_gpu.data<phi::dtype::float16>();
phi::dtype::float16* b = input2_gpu.data<phi::dtype::float16>();
phi::dtype::float16* c =
input3_gpu.mutable_data<phi::dtype::float16>(gpu_place);
GetBlas<phi::dtype::float16>(*context).GEMM(
false,
false,
m,
n,
k,
static_cast<phi::dtype::float16>(1),
a,
3,
b + 1,
4,
static_cast<phi::dtype::float16>(1),
c + 1,
4);
phi::Copy(*context, input3_gpu, cpu_place, true, &input3);
// numpy code:
// a = np.arange(6).reshape(2, 3)
// b = np.arange(12).reshape(3, 4)[:, 1:]
// c = np.arange(8).reshape(2, 4)[:, 1:]
// out = np.arange(8).reshape(2, 4)
// out[:, 1:] = np.dot(a, b) + c
context->Wait();
EXPECT_EQ(static_cast<float>(input3_ptr[0]), 0);
EXPECT_EQ(static_cast<float>(input3_ptr[1]), 24);
EXPECT_EQ(static_cast<float>(input3_ptr[2]), 28);
EXPECT_EQ(static_cast<float>(input3_ptr[3]), 32);
EXPECT_EQ(static_cast<float>(input3_ptr[4]), 4);
EXPECT_EQ(static_cast<float>(input3_ptr[5]), 73);
EXPECT_EQ(static_cast<float>(input3_ptr[6]), 86);
EXPECT_EQ(static_cast<float>(input3_ptr[7]), 99);
}
TEST(math_function, gemm_trans_cublas_fp32) {
phi::DenseTensor input1;
phi::DenseTensor input2;
phi::DenseTensor input3;
phi::DenseTensor input1_gpu;
phi::DenseTensor input2_gpu;
phi::DenseTensor input3_gpu;
phi::CPUPlace cpu_place;
phi::GPUPlace gpu_place(0);
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* context = reinterpret_cast<phi::GPUContext*>(pool.Get(phi::GPUPlace()));
int m = 2;
int n = 3;
int k = 3;
float* input1_ptr = input1.mutable_data<float>({2, 3}, cpu_place);
float arr1[6] = {0, 1, 2, 3, 4, 5};
memcpy(input1_ptr, arr1, 6 * sizeof(float));
float* input2_ptr = input2.mutable_data<float>({4, 3}, cpu_place);
float arr2[12] = {0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11};
memcpy(input2_ptr, arr2, 12 * sizeof(float));
float* input3_ptr = input3.mutable_data<float>({2, 4}, cpu_place);
float arr3[8] = {0, 1, 2, 3, 4, 5, 6, 7};
memcpy(input3_ptr, arr3, 8 * sizeof(float));
phi::Copy(*context, input1, gpu_place, true, &input1_gpu);
phi::Copy(*context, input2, gpu_place, true, &input2_gpu);
phi::Copy(*context, input3, gpu_place, true, &input3_gpu);
float* a = input1_gpu.data<float>();
float* b = input2_gpu.data<float>();
float* c = input3_gpu.mutable_data<float>(gpu_place);
GetBlas<float>(*context).GEMM(
false, true, m, n, k, 1, a, 3, b + 3, 3, 1, c + 1, 4);
phi::Copy(*context, input3_gpu, cpu_place, true, &input3);
context->Wait();
EXPECT_EQ(input3_ptr[0], 0);
EXPECT_EQ(input3_ptr[1], 24);
EXPECT_EQ(input3_ptr[2], 28);
EXPECT_EQ(input3_ptr[3], 32);
EXPECT_EQ(input3_ptr[4], 4);
EXPECT_EQ(input3_ptr[5], 73);
EXPECT_EQ(input3_ptr[6], 86);
EXPECT_EQ(input3_ptr[7], 99);
}
TEST(math_function, gemm_trans_cublas_fp16) {
phi::DenseTensor input1;
phi::DenseTensor input2;
phi::DenseTensor input3;
phi::DenseTensor input1_gpu;
phi::DenseTensor input2_gpu;
phi::DenseTensor input3_gpu;
phi::CPUPlace cpu_place;
phi::GPUPlace gpu_place(0);
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* context = reinterpret_cast<phi::GPUContext*>(pool.Get(phi::GPUPlace()));
// fp16 GEMM in cublas requires GPU compute capability >= 53
if (context->GetComputeCapability() < 53) {
return;
}
int m = 2;
int n = 3;
int k = 3;
phi::dtype::float16* input1_ptr =
input1.mutable_data<phi::dtype::float16>({2, 3}, cpu_place);
fill_fp16_data(input1_ptr, input1.numel(), {0, 1, 2, 3, 4, 5});
phi::dtype::float16* input2_ptr =
input2.mutable_data<phi::dtype::float16>({4, 3}, cpu_place);
fill_fp16_data(
input2_ptr, input2.numel(), {0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11});
phi::dtype::float16* input3_ptr =
input3.mutable_data<phi::dtype::float16>({2, 4}, cpu_place);
fill_fp16_data(input3_ptr, input3.numel(), {0, 1, 2, 3, 4, 5, 6, 7});
phi::Copy(*context, input1, gpu_place, true, &input1_gpu);
phi::Copy(*context, input2, gpu_place, true, &input2_gpu);
phi::Copy(*context, input3, gpu_place, true, &input3_gpu);
phi::dtype::float16* a = input1_gpu.data<phi::dtype::float16>();
phi::dtype::float16* b = input2_gpu.data<phi::dtype::float16>();
phi::dtype::float16* c =
input3_gpu.mutable_data<phi::dtype::float16>(gpu_place);
GetBlas<phi::dtype::float16>(*context).GEMM(
false,
true,
m,
n,
k,
static_cast<phi::dtype::float16>(1),
a,
3,
b + 3,
3,
static_cast<phi::dtype::float16>(1),
c + 1,
4);
phi::Copy(*context, input3_gpu, cpu_place, true, &input3);
context->Wait();
EXPECT_EQ(static_cast<float>(input3_ptr[0]), 0);
EXPECT_EQ(static_cast<float>(input3_ptr[1]), 24);
EXPECT_EQ(static_cast<float>(input3_ptr[2]), 28);
EXPECT_EQ(static_cast<float>(input3_ptr[3]), 32);
EXPECT_EQ(static_cast<float>(input3_ptr[4]), 4);
EXPECT_EQ(static_cast<float>(input3_ptr[5]), 73);
EXPECT_EQ(static_cast<float>(input3_ptr[6]), 86);
EXPECT_EQ(static_cast<float>(input3_ptr[7]), 99);
}
template <typename T>
void GemvTest(int m, int n, bool trans) {
phi::DenseTensor mat_a;
phi::DenseTensor vec_b;
phi::DenseTensor vec_c;
phi::CPUPlace cpu_place;
phi::GPUPlace gpu_place(0);
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* context = reinterpret_cast<phi::GPUContext*>(pool.Get(phi::GPUPlace()));
T* data_a = mat_a.mutable_data<T>({m, n}, cpu_place);
T* data_b = vec_b.mutable_data<T>({trans ? m : n}, cpu_place);
T* data_c = vec_c.mutable_data<T>({trans ? n : m}, cpu_place);
phi::DenseTensor g_mat_a;
phi::DenseTensor g_vec_b;
phi::DenseTensor g_vec_c;
T* g_data_a = g_mat_a.mutable_data<T>(mat_a.dims(), gpu_place);
T* g_data_b = g_vec_b.mutable_data<T>(vec_b.dims(), gpu_place);
T* g_data_c = g_vec_c.mutable_data<T>(vec_c.dims(), gpu_place);
for (int i = 0; i < mat_a.numel(); ++i) {
data_a[i] = static_cast<T>(i);
}
for (int i = 0; i < vec_b.numel(); ++i) {
data_b[i] = static_cast<T>(i);
}
phi::Copy(*context, mat_a, gpu_place, true, &g_mat_a);
phi::Copy(*context, vec_b, gpu_place, true, &g_vec_b);
GetBlas<T>(*context).GEMV(trans,
static_cast<int>(m),
static_cast<int>(n),
1.,
g_data_a,
g_data_b,
0.,
g_data_c);
phi::Copy(*context, g_vec_c, cpu_place, true, &vec_c);
if (!trans) {
for (int i = 0; i < m; ++i) {
T sum = 0.0;
for (int j = 0; j < n; ++j) {
sum += data_a[i * n + j] * data_b[j];
}
ASSERT_FLOAT_EQ(data_c[i], sum);
}
} else {
for (int i = 0; i < n; ++i) {
T sum = 0.0;
for (int j = 0; j < m; ++j) {
sum += data_a[j * n + i] * data_b[j];
}
ASSERT_FLOAT_EQ(data_c[i], sum);
}
}
}
TEST(math_function, gemv) {
GemvTest<float>(3, 13, false);
GemvTest<double>(3, 13, false);
GemvTest<float>(3, 13, true);
GemvTest<double>(3, 13, true);
}
} // namespace tests
} // namespace phi
@@ -0,0 +1,79 @@
// 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 <gtest/gtest.h>
#include <memory>
#include "paddle/phi/api/lib/utils/allocator.h"
#include "paddle/phi/backends/context_pool.h"
#include "paddle/phi/backends/gpu/gpu_context.h"
#include "paddle/phi/common/place.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/device_context.h"
#include "paddle/phi/kernels/memcpy_kernel.h"
namespace phi {
namespace tests {
using DDim = phi::DDim;
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
TEST(DEV_API, memcpy_d2h) {
// 1. create tensor
const auto cpu_alloc =
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace());
phi::DenseTensor x_cpu(cpu_alloc.get(),
phi::DenseTensorMeta(phi::DataType::FLOAT32,
common::make_ddim({3, 2, 2, 3}),
phi::DataLayout::NCHW));
auto& pool = phi::DeviceContextPool::Instance();
auto* cpu_ctx = pool.GetByPlace(phi::CPUPlace());
auto* x_cpu_data = cpu_ctx->template Alloc<float>(&x_cpu);
for (int i = 0; i < x_cpu.numel(); i++) {
x_cpu_data[i] = static_cast<float>(i);
}
const auto alloc =
std::make_unique<paddle::experimental::DefaultAllocator>(phi::GPUPlace());
phi::DenseTensor x;
// 2. test API
auto* dev_ctx = pool.GetByPlace(phi::GPUPlace());
phi::MemcpyH2DKernel<phi::GPUContext>(*dev_ctx, x_cpu, 1, &x);
phi::DenseTensor out;
phi::MemcpyD2HKernel<phi::GPUContext>(*dev_ctx, x, 1, &out);
// 3. check result
std::vector<int64_t> expect_shape = {12, 3};
ASSERT_EQ(out.dims(), x.dims());
ASSERT_EQ(out.meta().dtype, phi::DataType::FLOAT32);
ASSERT_EQ(out.meta().layout, phi::DataLayout::NCHW);
bool value_equal = true;
auto* dense_out_data = out.data<float>();
for (int i = 0; i < x_cpu.numel(); i++) {
if (x_cpu_data[i] != dense_out_data[i]) {
value_equal = false;
break;
}
}
ASSERT_EQ(value_equal, true);
}
#endif
} // namespace tests
} // namespace phi
@@ -0,0 +1,67 @@
/* 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 <gtest/gtest.h>
#include <algorithm>
#include <memory>
#include <string>
#include "paddle/phi/api/lib/utils/allocator.h"
#include "paddle/phi/backends/context_pool.h"
#include "paddle/phi/common/pstring.h"
#include "paddle/phi/core/string_tensor.h"
#include "paddle/phi/kernels/strings/strings_copy_kernel.h"
namespace phi {
namespace tests {
using DDim = phi::DDim;
using pstring = phi::dtype::pstring;
TEST(DEV_API, strings_copy) {
// 1. create tensor
const DDim dims({2, 3});
StringTensorMeta meta(dims);
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* dev_ctx = reinterpret_cast<phi::CPUContext*>(pool.Get(phi::CPUPlace()));
const auto string_allocator =
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace());
const auto alloc = string_allocator.get();
StringTensor string_src(alloc, meta);
StringTensor string_dst(alloc, meta);
// 2. Assign input text
const char* input[] = {"A Short Pstring.", // NOLINT
"A Large Pstring Whose Length Is Longer Than 22.",
"abc",
"defg",
"hijklmn",
"opqrst"};
pstring* string_src_data = dev_ctx->template Alloc<pstring>(&string_src);
for (int i = 0; i < string_src.numel(); ++i) {
string_src_data[i] = input[i];
}
phi::strings::Copy(*dev_ctx, string_src, false, &string_dst);
for (int64_t i = 0; i < string_src.numel(); i++) {
ASSERT_EQ(string_src.data()[i], string_dst.data()[i]);
}
}
} // namespace tests
} // namespace phi
@@ -0,0 +1,73 @@
/* 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 <gtest/gtest.h>
#include <algorithm>
#include <memory>
#include <string>
#include "paddle/phi/api/lib/utils/allocator.h"
#include "paddle/phi/backends/context_pool.h"
#include "paddle/phi/common/pstring.h"
#include "paddle/phi/core/string_tensor.h"
#include "paddle/phi/kernels/strings/strings_copy_kernel.h"
#include "paddle/phi/kernels/strings/strings_empty_kernel.h"
namespace phi {
namespace tests {
using DDim = phi::DDim;
using pstring = phi::dtype::pstring;
TEST(DEV_API, strings_copy) {
// 1. create tensor
const DDim dims({2, 3});
StringTensorMeta meta(dims);
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* dev_ctx = reinterpret_cast<phi::CPUContext*>(pool.Get(phi::CPUPlace()));
auto* gpu_dev_ctx =
reinterpret_cast<phi::GPUContext*>(pool.Get(phi::GPUPlace()));
StringTensor string_src = phi::strings::Empty(*dev_ctx, std::move(meta));
StringTensor string_dst = phi::strings::Empty(*dev_ctx, std::move(meta));
// 2. Assign input text
const char* input[] = {"A Short Pstring.",
"A Large Pstring Whose Length Is Longer Than 22.",
"abc",
"defg",
"hijklmn",
"opqrst"};
pstring* string_src_data = dev_ctx->template Alloc<pstring>(&string_src);
for (int i = 0; i < string_src.numel(); ++i) {
string_src_data[i] = input[i];
}
StringTensor string_gpu1 = phi::strings::Empty(*gpu_dev_ctx, std::move(meta));
StringTensor string_gpu2 = phi::strings::Empty(*gpu_dev_ctx, std::move(meta));
// cpu->gpu
phi::strings::Copy(*gpu_dev_ctx, string_src, false, &string_gpu1);
// gpu->gpu
phi::strings::Copy(*gpu_dev_ctx, string_gpu1, false, &string_gpu2);
// gpu->cpu
phi::strings::Copy(*gpu_dev_ctx, string_gpu2, false, &string_dst);
for (int64_t i = 0; i < string_src.numel(); i++) {
ASSERT_EQ(string_src.data()[i], string_dst.data()[i]);
}
}
} // namespace tests
} // namespace phi
@@ -0,0 +1,136 @@
/* 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 <gtest/gtest.h>
#include <algorithm>
#include <memory>
#include <string>
#include "glog/logging.h"
#include "paddle/phi/api/lib/utils/allocator.h"
#include "paddle/phi/backends/context_pool.h"
#include "paddle/phi/common/data_type.h"
#include "paddle/phi/common/pstring.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/core/string_tensor.h"
#include "paddle/phi/kernels/strings/strings_empty_kernel.h"
#include "paddle/phi/kernels/strings/strings_lower_upper_kernel.h"
namespace phi {
namespace tests {
using DDim = phi::DDim;
using pstring = ::phi::dtype::pstring;
TEST(DEV_API, strings_cast_convert) {
// 1. create tensor
const DDim dims({1, 2});
StringTensorMeta meta(dims);
const auto string_allocator =
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace());
const auto alloc = string_allocator.get();
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* dev_ctx = pool.Get(phi::CPUPlace());
StringTensor dense_x(alloc, meta);
std::string short_str = "A Short Pstring.";
std::string long_str = "A Large Pstring Whose Length Is Longer Than 22.";
pstring* dense_x_data = dev_ctx->template Alloc<pstring>(&dense_x);
dense_x_data[0] = short_str;
dense_x_data[1] = long_str;
// 2. get expected results
std::string expected_results[] = {// NOLINT
short_str,
short_str,
long_str,
long_str};
std::transform(short_str.begin(),
short_str.end(),
expected_results[0].begin(),
::tolower);
std::transform(short_str.begin(),
short_str.end(),
expected_results[1].begin(),
::toupper);
std::transform(
long_str.begin(), long_str.end(), expected_results[2].begin(), ::tolower);
std::transform(
long_str.begin(), long_str.end(), expected_results[3].begin(), ::toupper);
// 3. test API, ascii encoding
auto dense_lower_out = phi::strings::StringLower(
*(static_cast<phi::CPUContext*>(dev_ctx)), dense_x, false);
auto dense_upper_out = phi::strings::StringUpper(
*(static_cast<phi::CPUContext*>(dev_ctx)), dense_x, false);
// 4. check results
ASSERT_EQ(dense_lower_out.numel(), 2);
ASSERT_EQ(dense_upper_out.numel(), 2);
// lower case
ASSERT_EQ(dense_lower_out.data()[0].data(), expected_results[0]);
ASSERT_EQ(dense_lower_out.data()[1].data(), expected_results[2]);
// upper case
ASSERT_EQ(dense_upper_out.data()[0].data(), expected_results[1]);
ASSERT_EQ(dense_upper_out.data()[1].data(), expected_results[3]);
}
TEST(DEV_API, strings_cast_convert_utf8) {
// 1. create tensor
const DDim dims({1, 1});
StringTensorMeta meta(dims);
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* dev_ctx = pool.Get(phi::CPUPlace());
const auto string_allocator =
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace());
const auto alloc = string_allocator.get();
StringTensor dense_x(alloc, meta);
std::string utf8_str = "óÓsscHloëËóÓsscHloëËóÓsscHloëË";
pstring* dense_x_data = dev_ctx->template Alloc<pstring>(&dense_x);
dense_x_data[0] = utf8_str;
// 2. get expected results
std::string expected_results[] = {// NOLINT
"óósschloëëóósschloëëóósschloëë",
"ÓÓSSCHLOËËÓÓSSCHLOËËÓÓSSCHLOËË"};
// 3. test API, ascii encoding
auto dense_lower_out = phi::strings::StringLower(
*(static_cast<phi::CPUContext*>(dev_ctx)), dense_x, true);
auto dense_upper_out = phi::strings::StringUpper(
*(static_cast<phi::CPUContext*>(dev_ctx)), dense_x, true);
// 4. check results
ASSERT_EQ(dense_lower_out.numel(), 1);
ASSERT_EQ(dense_upper_out.numel(), 1);
// lower case
VLOG(0) << dense_lower_out.data()[0].data();
ASSERT_EQ(dense_lower_out.data()[0].data(), expected_results[0]);
// upper case
ASSERT_EQ(dense_upper_out.data()[0].data(), expected_results[1]);
}
} // namespace tests
} // namespace phi
@@ -0,0 +1,161 @@
/* 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 <gtest/gtest.h>
#include <stdio.h>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
#if (defined(__NVCC__) || defined(__HIPCC__))
#include <thrust/device_vector.h>
#include <thrust/execution_policy.h>
#endif
#include "paddle/phi/api/lib/utils/allocator.h"
#include "paddle/phi/backends/context_pool.h"
#include "paddle/phi/backends/gpu/gpu_helper.h"
#include "paddle/phi/common/data_type.h"
#include "paddle/phi/common/pstring.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/core/string_tensor.h"
#include "paddle/phi/kernels/strings/strings_copy_kernel.h"
#include "paddle/phi/kernels/strings/strings_empty_kernel.h"
#include "paddle/phi/kernels/strings/strings_lower_upper_kernel.h"
namespace phi {
namespace tests {
namespace framework = paddle::framework;
using DDim = phi::DDim;
using pstring = ::phi::dtype::pstring;
using phi::CPUPlace;
using phi::GPUPlace;
TEST(DEV_API, strings_cast_convert) {
auto gpu0 = GPUPlace();
auto cpu = CPUPlace();
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
GPUContext* dev_ctx = reinterpret_cast<GPUContext*>(pool.Get(gpu0));
CPUContext* cpu_ctx = reinterpret_cast<CPUContext*>(pool.Get(cpu));
// 1. create tensor
const DDim dims({1, 2});
StringTensorMeta meta(dims);
StringTensor gpu_strings_x = phi::strings::Empty(*dev_ctx, std::move(meta));
StringTensor cpu_strings_x = phi::strings::Empty(*cpu_ctx, std::move(meta));
StringTensor cpu_strings_lower_out =
phi::strings::Empty(*cpu_ctx, std::move(meta));
StringTensor cpu_strings_upper_out =
phi::strings::Empty(*cpu_ctx, std::move(meta));
std::string short_str = "A Short Pstring.";
std::string long_str = "A Large Pstring Whose Length Is Longer Than 22.";
pstring* cpu_strings_x_data =
cpu_ctx->template Alloc<pstring>(&cpu_strings_x);
cpu_strings_x_data[0] = short_str;
cpu_strings_x_data[1] = long_str;
phi::strings::Copy(*dev_ctx, cpu_strings_x, false, &gpu_strings_x);
// 2. get expected results
std::string expected_results[] = {short_str, short_str, long_str, long_str};
std::transform(short_str.begin(),
short_str.end(),
expected_results[0].begin(),
::tolower);
std::transform(short_str.begin(),
short_str.end(),
expected_results[1].begin(),
::toupper);
std::transform(
long_str.begin(), long_str.end(), expected_results[2].begin(), ::tolower);
std::transform(
long_str.begin(), long_str.end(), expected_results[3].begin(), ::toupper);
// 3. test API, ascii encoding
auto gpu_strings_lower_out =
phi::strings::StringLower(*dev_ctx, gpu_strings_x, false);
auto gpu_strings_upper_out =
phi::strings::StringUpper(*dev_ctx, gpu_strings_x, false);
phi::strings::Copy(
*dev_ctx, gpu_strings_lower_out, false, &cpu_strings_lower_out);
phi::strings::Copy(
*dev_ctx, gpu_strings_upper_out, false, &cpu_strings_upper_out);
// 4. check results
ASSERT_EQ(gpu_strings_lower_out.numel(), 2);
ASSERT_EQ(gpu_strings_upper_out.numel(), 2);
const char* cpu_results[] = {cpu_strings_lower_out.data()[0].data(),
cpu_strings_upper_out.data()[0].data(),
cpu_strings_lower_out.data()[1].data(),
cpu_strings_upper_out.data()[1].data()};
for (int i = 0; i < 4; ++i) {
ASSERT_EQ(cpu_results[i], expected_results[i]);
}
}
TEST(DEV_API, strings_cast_convert_utf8) {
auto gpu0 = GPUPlace();
auto cpu = CPUPlace();
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
GPUContext* dev_ctx = reinterpret_cast<GPUContext*>(pool.Get(gpu0));
CPUContext* cpu_ctx = reinterpret_cast<CPUContext*>(pool.Get(cpu));
// 1. create tensor
const DDim dims({1, 1});
StringTensorMeta meta(dims);
StringTensor gpu_strings_x = phi::strings::Empty(*dev_ctx, std::move(meta));
StringTensor cpu_strings_x = phi::strings::Empty(*cpu_ctx, std::move(meta));
StringTensor cpu_strings_lower_out =
phi::strings::Empty(*cpu_ctx, std::move(meta));
StringTensor cpu_strings_upper_out =
phi::strings::Empty(*cpu_ctx, std::move(meta));
std::string utf8_str = "óÓsscHloëË";
pstring* cpu_strings_x_data =
cpu_ctx->template Alloc<pstring>(&cpu_strings_x);
cpu_strings_x_data[0] = utf8_str;
phi::strings::Copy(*dev_ctx, cpu_strings_x, false, &gpu_strings_x);
// 2. get expected results
std::string expected_results[] = {"óósschloëë", "ÓÓSSCHLOËË"};
// 3. test API, ascii encoding
auto gpu_strings_lower_out =
phi::strings::StringLower(*dev_ctx, gpu_strings_x, true);
auto gpu_strings_upper_out =
phi::strings::StringUpper(*dev_ctx, gpu_strings_x, true);
phi::strings::Copy(
*dev_ctx, gpu_strings_lower_out, false, &cpu_strings_lower_out);
phi::strings::Copy(
*dev_ctx, gpu_strings_upper_out, false, &cpu_strings_upper_out);
// 4. check results
const char* cpu_results[] = {cpu_strings_lower_out.data()[0].data(),
cpu_strings_upper_out.data()[0].data()};
ASSERT_EQ(cpu_strings_lower_out.numel(), 1);
ASSERT_EQ(cpu_strings_upper_out.numel(), 1);
for (int i = 0; i < 2; ++i) {
ASSERT_EQ(cpu_results[i], expected_results[i]);
}
}
} // namespace tests
} // namespace phi
@@ -0,0 +1,221 @@
// 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 <gtest/gtest.h>
#include <vector>
#include "glog/logging.h"
#include "paddle/phi/api/lib/utils/allocator.h"
#include "paddle/phi/backends/context_pool.h"
#include "paddle/phi/core/tensor_utils.h"
#include "paddle/phi/kernels/funcs/broadcast_function.h"
template <typename T>
struct AddTernary_1 {
inline HOSTDEVICE T operator()(T a, T b, T c) const { return a + b + c; }
};
template <typename T>
struct AddTernary_2 {
inline HOSTDEVICE T operator()(T a, T b, T c) const { return a + b + c; }
};
template <typename T>
struct AddTernary_3 {
inline HOSTDEVICE T operator()(T a, T b, T c) const { return a + b + c; }
};
template <typename T>
void InitValue(T* data, size_t numel, const int val) {
for (auto i = 0; i < numel; ++i) {
data[i] = static_cast<T>(val);
}
}
template <typename T, typename Func>
void TestCase(const phi::GPUContext& dev_ctx,
const phi::DDim& dim1,
const phi::DDim& dim2,
const phi::DDim& dim3,
const phi::DDim& dim_out,
const size_t times,
Func compute) {
phi::DataType dtype = phi::CppTypeToDataType<T>::Type();
const auto alloc_cpu =
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace());
const auto alloc_gpu =
std::make_unique<paddle::experimental::DefaultAllocator>(phi::GPUPlace());
auto in1 = std::make_shared<phi::DenseTensor>(
alloc_cpu.get(),
phi::DenseTensorMeta(dtype, dim1, phi::DataLayout::NCHW));
auto in2 = std::make_shared<phi::DenseTensor>(
alloc_cpu.get(),
phi::DenseTensorMeta(dtype, dim2, phi::DataLayout::NCHW));
auto in3 = std::make_shared<phi::DenseTensor>(
alloc_cpu.get(),
phi::DenseTensorMeta(dtype, dim3, phi::DataLayout::NCHW));
InitValue(in1->data<T>(), in1->numel(), 1);
InitValue(in2->data<T>(), in2->numel(), 1);
InitValue(in3->data<T>(), in3->numel(), 1);
auto d_in1 = std::make_shared<phi::DenseTensor>(
alloc_gpu.get(),
phi::DenseTensorMeta(dtype, dim1, phi::DataLayout::NCHW));
auto d_in2 = std::make_shared<phi::DenseTensor>(
alloc_gpu.get(),
phi::DenseTensorMeta(dtype, dim2, phi::DataLayout::NCHW));
auto d_in3 = std::make_shared<phi::DenseTensor>(
alloc_gpu.get(),
phi::DenseTensorMeta(dtype, dim3, phi::DataLayout::NCHW));
auto d_out = std::make_shared<phi::DenseTensor>(
alloc_gpu.get(),
phi::DenseTensorMeta(dtype, dim_out, phi::DataLayout::NCHW));
phi::Copy(dev_ctx, *in1.get(), phi::GPUPlace(), false, d_in1.get());
phi::Copy(dev_ctx, *in2.get(), phi::GPUPlace(), false, d_in2.get());
phi::Copy(dev_ctx, *in3.get(), phi::GPUPlace(), false, d_in3.get());
std::vector<const phi::DenseTensor*> inputs{
d_in1.get(), d_in2.get(), d_in3.get()};
std::vector<phi::DenseTensor*> outputs{d_out.get()};
for (int i = 0; i < times; ++i) {
phi::funcs::BroadcastKernel<T>(dev_ctx, inputs, &outputs, compute);
}
dev_ctx.Wait();
}
TEST(Broadcast, add) {
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
auto place = phi::GPUPlace();
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* dev_ctx = static_cast<const phi::GPUContext*>(pool.GetByPlace(place));
size_t times = 10;
do {
auto dim1 = common::make_ddim({1, 2048, 3584});
auto dim2 = common::make_ddim({1, 2048, 1});
auto dim3 = common::make_ddim({1, 1, 3584});
auto dim_out = common::make_ddim({1, 2048, 3584});
TestCase<float>(
*dev_ctx, dim1, dim2, dim3, dim_out, times, AddTernary_1<float>());
TestCase<phi::dtype::float16>(*dev_ctx,
dim1,
dim2,
dim3,
dim_out,
times,
AddTernary_1<phi::dtype::float16>());
TestCase<phi::dtype::bfloat16>(*dev_ctx,
dim1,
dim2,
dim3,
dim_out,
times,
AddTernary_1<phi::dtype::bfloat16>());
TestCase<phi::dtype::complex<float>>(
*dev_ctx,
dim1,
dim2,
dim3,
dim_out,
times,
AddTernary_1<phi::dtype::complex<float>>());
TestCase<phi::dtype::complex<double>>(
*dev_ctx,
dim1,
dim2,
dim3,
dim_out,
times,
AddTernary_1<phi::dtype::complex<double>>());
} while (0);
do {
auto dim1 = common::make_ddim({1, 256, 4, 256, 256});
auto dim2 = common::make_ddim({1, 256, 1, 1, 256});
auto dim3 = common::make_ddim({1, 1, 4, 256, 256});
auto dim_out = common::make_ddim({1, 256, 4, 256, 256});
TestCase<float>(
*dev_ctx, dim1, dim2, dim3, dim_out, times, AddTernary_2<float>());
TestCase<phi::dtype::float16>(*dev_ctx,
dim1,
dim2,
dim3,
dim_out,
times,
AddTernary_2<phi::dtype::float16>());
TestCase<phi::dtype::bfloat16>(*dev_ctx,
dim1,
dim2,
dim3,
dim_out,
times,
AddTernary_2<phi::dtype::bfloat16>());
TestCase<phi::dtype::complex<float>>(
*dev_ctx,
dim1,
dim2,
dim3,
dim_out,
times,
AddTernary_2<phi::dtype::complex<float>>());
TestCase<phi::dtype::complex<double>>(
*dev_ctx,
dim1,
dim2,
dim3,
dim_out,
times,
AddTernary_2<phi::dtype::complex<double>>());
} while (0);
do {
auto dim1 = common::make_ddim({1, 256, 256});
auto dim2 = common::make_ddim({1, 1, 256});
auto dim3 = common::make_ddim({1, 256, 1});
auto dim_out = common::make_ddim({1, 256, 256});
TestCase<float>(
*dev_ctx, dim1, dim2, dim3, dim_out, times, AddTernary_3<float>());
TestCase<phi::dtype::float16>(*dev_ctx,
dim1,
dim2,
dim3,
dim_out,
times,
AddTernary_3<phi::dtype::float16>());
TestCase<phi::dtype::bfloat16>(*dev_ctx,
dim1,
dim2,
dim3,
dim_out,
times,
AddTernary_3<phi::dtype::bfloat16>());
TestCase<phi::dtype::complex<float>>(
*dev_ctx,
dim1,
dim2,
dim3,
dim_out,
times,
AddTernary_3<phi::dtype::complex<float>>());
TestCase<phi::dtype::complex<double>>(
*dev_ctx,
dim1,
dim2,
dim3,
dim_out,
times,
AddTernary_3<phi::dtype::complex<double>>());
} while (0);
#endif
}
@@ -0,0 +1,74 @@
// 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 <gtest/gtest.h>
#include <memory>
#include "paddle/phi/api/lib/utils/allocator.h"
#include "paddle/phi/backends/context_pool.h"
#include "paddle/phi/backends/gpu/gpu_context.h"
#include "paddle/phi/common/place.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/device_context.h"
#include "paddle/phi/infermeta/unary.h"
#include "paddle/phi/kernels/transfer_layout_kernel.h"
namespace phi {
namespace tests {
#ifdef PADDLE_WITH_DNNL
TEST(DEV_API, transfer_layout) {
// 1. create tensor
const int n = 2;
const int c = 3;
const int h = 4;
const int w = 5;
DenseTensor x;
MetaTensor meta_x(&x);
meta_x.set_dtype(DataType::FLOAT32);
meta_x.set_layout(DataLayout::ONEDNN);
meta_x.set_dims(common::make_ddim({n, c, h, w}));
DenseTensor out;
// 2. test API
auto& pool = phi::DeviceContextPool::Instance();
auto place = phi::CPUPlace();
auto* dev_ctx = static_cast<const phi::CPUContext*>(pool.GetByPlace(place));
MetaTensor meta_out(&out);
TransferLayoutInferMeta(x,
static_cast<int>(x.layout()),
static_cast<int>(DataLayout::NHWC),
&meta_out);
TransferLayoutKernel<CPUContext>(*dev_ctx,
x,
static_cast<int>(x.layout()),
static_cast<int>(DataLayout::NHWC),
&out);
// 3. check result
std::vector<int64_t> expect_shape = {12, 3};
ASSERT_EQ(out.dims(), common::make_ddim({n, h, w, c}));
ASSERT_EQ(out.dims().size(), 4);
ASSERT_EQ(out.meta().dtype, DataType::FLOAT32);
ASSERT_EQ(out.meta().layout, DataLayout::NHWC);
}
#endif
} // namespace tests
} // namespace phi