chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/abs_grad_kernel.h"
|
||||
|
||||
#include "paddle/phi/common/type_traits.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/abs_grad_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(abs_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AbsGradKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {
|
||||
kernel->InputAt(1).SetDataType(phi::dtype::ToReal(kernel_key.dtype()));
|
||||
}
|
||||
PD_REGISTER_KERNEL(abs_double_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AbsDoubleGradKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::complex64,
|
||||
phi::complex128) {
|
||||
kernel->InputAt(1).SetDataType(phi::dtype::ToReal(kernel_key.dtype()));
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/abs_kernel.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/complex_functors.h"
|
||||
#include "paddle/phi/kernels/funcs/elementwise_base.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct CudaAbsFunctor;
|
||||
|
||||
template <typename T>
|
||||
struct CudaAbsFunctor<T, funcs::Complex<T, dtype::Real<T>>> {
|
||||
__device__ __forceinline__ dtype::Real<T> operator()(const T x) const {
|
||||
return abs(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct CudaAbsFunctor<T,
|
||||
std::enable_if_t<std::is_same<T, dtype::Real<T>>::value &&
|
||||
std::is_same<T, bfloat16>::value>> {
|
||||
__device__ __forceinline__ T operator()(const T x) const { return abs(x); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct CudaAbsFunctor<T,
|
||||
std::enable_if_t<std::is_same<T, dtype::Real<T>>::value &&
|
||||
!std::is_same<T, bfloat16>::value>> {
|
||||
__device__ __forceinline__ T operator()(const T x) const {
|
||||
return std::abs(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Context>
|
||||
PADDLE_API void AbsKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
DenseTensor* out) {
|
||||
dev_ctx.template Alloc<dtype::Real<T>>(out);
|
||||
std::vector<const DenseTensor*> ins = {&x};
|
||||
std::vector<DenseTensor*> outs = {out};
|
||||
auto functor = CudaAbsFunctor<T>();
|
||||
|
||||
funcs::ElementwiseKernel<dtype::Real<T>>(dev_ctx, ins, &outs, functor);
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(abs,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AbsKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {
|
||||
kernel->OutputAt(0).SetDataType(phi::dtype::ToReal(kernel_key.dtype()));
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2024 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/accuracy_check_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/common/data_type.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/accuracy_check_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(accuracy_check,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AccuracyCheckKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
uint8_t,
|
||||
int8_t,
|
||||
int16_t,
|
||||
bool,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
@@ -0,0 +1,146 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/accuracy_kernel.h"
|
||||
|
||||
#include <thrust/execution_policy.h>
|
||||
#include <thrust/reduce.h>
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_info.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <int BlockSize, typename T>
|
||||
__global__ void AccuracyCudaKernel(const int64_t N,
|
||||
const int D,
|
||||
const int64_t* Xdata,
|
||||
const int64_t* labeldata,
|
||||
int* correct_data,
|
||||
T* accuracy,
|
||||
int* total_data) {
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
int count = 0;
|
||||
__shared__ int total[BlockSize];
|
||||
|
||||
// support only 1 block
|
||||
for (int64_t i = threadIdx.x; i < (N); i += BlockSize) {
|
||||
for (int j = 0; j < D; ++j) {
|
||||
if (Xdata[i * D + j] == labeldata[i]) {
|
||||
++count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
total[threadIdx.x] = count;
|
||||
__syncthreads();
|
||||
|
||||
// reduce the count with init value 0, and output accuracy.
|
||||
#ifdef PADDLE_WITH_CUDA
|
||||
int result = thrust::reduce(thrust::device, total, total + BlockSize, 0);
|
||||
#else
|
||||
// HIP thrust::reduce not support __device__
|
||||
for (int s = BlockSize / 2; s > 0; s >>= 1) {
|
||||
if (threadIdx.x < s) {
|
||||
total[threadIdx.x] += total[threadIdx.x + s];
|
||||
}
|
||||
__syncthreads();
|
||||
}
|
||||
int result = total[0];
|
||||
#endif
|
||||
if (threadIdx.x == 0) {
|
||||
*correct_data = result;
|
||||
*accuracy = static_cast<T>(static_cast<MT>(result) / static_cast<MT>(N));
|
||||
*total_data = N;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AccuracyKernel(const Context& dev_ctx,
|
||||
const DenseTensor& inference,
|
||||
const DenseTensor& indices,
|
||||
const DenseTensor& label,
|
||||
DenseTensor* accuracy,
|
||||
DenseTensor* correct,
|
||||
DenseTensor* total) {
|
||||
// FIXME(typhoonzero): only support indices currently
|
||||
// if add support for output values, how to detect the data type?
|
||||
const int64_t* indices_data = indices.data<int64_t>();
|
||||
const int64_t* label_data = label.data<int64_t>();
|
||||
|
||||
PADDLE_ENFORCE_EQ(
|
||||
inference.dims().size(),
|
||||
2,
|
||||
common::errors::InvalidArgument(
|
||||
"Rank(Input) of AccuracyOp must be 2, with shape "
|
||||
"[sample_number, class_dim], But received rank(Input) is %d",
|
||||
inference.dims().size()));
|
||||
|
||||
int* correct_data = dev_ctx.template Alloc<int>(correct);
|
||||
int* total_data = dev_ctx.template Alloc<int>(total);
|
||||
T* accuracy_data = dev_ctx.template Alloc<T>(accuracy);
|
||||
|
||||
int64_t num_samples = inference.dims()[0];
|
||||
size_t infer_width = inference.dims()[1];
|
||||
auto stream = dev_ctx.stream();
|
||||
backends::gpu::GpuMemsetAsync(accuracy_data, 0, sizeof(T), stream);
|
||||
|
||||
PADDLE_ENFORCE_GT(label.dims().size(),
|
||||
0,
|
||||
common::errors::InvalidArgument(
|
||||
"Rank(Label) of AccuracyOp must greater than 0, "
|
||||
"But received rank(Label) is %d",
|
||||
label.dims().size()));
|
||||
|
||||
PADDLE_ENFORCE_GE(label.dims()[0],
|
||||
inference.dims()[0],
|
||||
common::errors::InvalidArgument(
|
||||
"num_samples(%d) of Label should less than "
|
||||
"or equal to num_samples(%d) of Input",
|
||||
label.dims()[0],
|
||||
num_samples));
|
||||
|
||||
if (num_samples == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
AccuracyCudaKernel<PADDLE_CUDA_NUM_THREADS, T>
|
||||
<<<1, PADDLE_CUDA_NUM_THREADS, 0, stream>>>(num_samples,
|
||||
infer_width,
|
||||
indices_data,
|
||||
label_data,
|
||||
correct_data,
|
||||
accuracy_data,
|
||||
total_data);
|
||||
}
|
||||
} // namespace phi
|
||||
|
||||
// FIXME(typhoonzero): types of T is for inference data.
|
||||
// label data is always int64
|
||||
PD_REGISTER_KERNEL(accuracy,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AccuracyKernel,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
float,
|
||||
double) {
|
||||
kernel->InputAt(1).SetDataType(phi::DataType::INT64);
|
||||
kernel->InputAt(2).SetDataType(phi::DataType::INT64);
|
||||
kernel->OutputAt(1).SetDataType(phi::DataType::INT32);
|
||||
kernel->OutputAt(2).SetDataType(phi::DataType::INT32);
|
||||
}
|
||||
@@ -0,0 +1,759 @@
|
||||
/* Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. */
|
||||
|
||||
#include "paddle/phi/kernels/activation_grad_kernel.h"
|
||||
#include "paddle/common/flags.h"
|
||||
|
||||
#include "glog/logging.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_device_function.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/full_kernel.h"
|
||||
#include "paddle/phi/kernels/funcs/elementwise_base.h"
|
||||
#include "paddle/phi/kernels/impl/activation_grad_impl.h"
|
||||
|
||||
COMMON_DECLARE_bool(use_accuracy_compatible_kernel);
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context, typename Functor>
|
||||
void ActivationGradGPUImpl(const Context& dev_ctx,
|
||||
const DenseTensor* x,
|
||||
const DenseTensor* out,
|
||||
const DenseTensor* d_out,
|
||||
DenseTensor* d_x,
|
||||
const Functor& functor) {
|
||||
if (static_cast<int>(Functor::FwdDeps()) &
|
||||
static_cast<int>(funcs::ActBwdOpFwdDeps::kDepOut)) {
|
||||
PADDLE_ENFORCE_NOT_NULL(
|
||||
out, errors::NotFound("The input DenseTensor Out can not be nullptr"));
|
||||
}
|
||||
PADDLE_ENFORCE_NOT_NULL(
|
||||
d_out, errors::NotFound("The input DenseTensor dOut can not be nullptr"));
|
||||
PADDLE_ENFORCE_NOT_NULL(
|
||||
d_x, errors::NotFound("The output DenseTensor dX can not be nullptr"));
|
||||
|
||||
if (!out) {
|
||||
out = d_out; // fake out
|
||||
}
|
||||
if (static_cast<int>(Functor::FwdDeps()) &
|
||||
static_cast<int>(funcs::ActBwdOpFwdDeps::kDepX)) {
|
||||
PADDLE_ENFORCE_NOT_NULL(
|
||||
x, errors::NotFound("The input DenseTensor X can not be nullptr"));
|
||||
} else {
|
||||
VLOG(10) << "Inplace activation of Op Functor: " << typeid(Functor).name();
|
||||
x = d_x;
|
||||
}
|
||||
|
||||
dev_ctx.template Alloc<T>(d_x);
|
||||
if (d_x->numel() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<const DenseTensor*> ins = {d_out};
|
||||
std::vector<DenseTensor*> outs = {d_x};
|
||||
|
||||
if (static_cast<int>(Functor::FwdDeps()) ==
|
||||
static_cast<int>(funcs::ActBwdOpFwdDeps::kDepOut)) {
|
||||
// Only need forward output Out
|
||||
ins.push_back(out);
|
||||
funcs::ElementwiseKernel<T>(dev_ctx, ins, &outs, functor);
|
||||
} else if (static_cast<int>(Functor::FwdDeps()) ==
|
||||
static_cast<int>(funcs::ActBwdOpFwdDeps::kDepX)) {
|
||||
// Only need forward input X
|
||||
ins.push_back(x);
|
||||
funcs::ElementwiseKernel<T>(dev_ctx, ins, &outs, functor);
|
||||
} else {
|
||||
funcs::ElementwiseKernel<T>(dev_ctx, ins, &outs, functor);
|
||||
}
|
||||
}
|
||||
|
||||
#define DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(name, functor_class) \
|
||||
template <typename T, typename Context> \
|
||||
void name##GradKernel(const Context& dev_ctx, \
|
||||
const DenseTensor& x, \
|
||||
const DenseTensor& dout, \
|
||||
DenseTensor* dx) { \
|
||||
funcs::functor_class<T> functor; \
|
||||
ActivationGradGPUImpl<T, Context, funcs::functor_class<T>>( \
|
||||
dev_ctx, &x, nullptr, &dout, dx, functor); \
|
||||
}
|
||||
|
||||
#define DEFINE_GPU_ACT_GRAD_KERNEL_WITH_ONE_ATTRS_DEPX( \
|
||||
name, functor_class, attr) \
|
||||
template <typename T, typename Context> \
|
||||
void name##GradKernel(const Context& dev_ctx, \
|
||||
const DenseTensor& x, \
|
||||
const DenseTensor& dout, \
|
||||
float attr, \
|
||||
DenseTensor* dx) { \
|
||||
funcs::functor_class<T> functor; \
|
||||
auto attrs = functor.GetAttrs(); \
|
||||
*(attrs[0].second) = attr; \
|
||||
ActivationGradGPUImpl<T, Context, funcs::functor_class<T>>( \
|
||||
dev_ctx, &x, nullptr, &dout, dx, functor); \
|
||||
}
|
||||
|
||||
#define DEFINE_GPU_ACT_GRAD_KERNEL_WITH_ONE_DOUBLE_ATTRS_DEPX( \
|
||||
name, functor_class, attr) \
|
||||
template <typename T, typename Context> \
|
||||
void name##GradKernel(const Context& dev_ctx, \
|
||||
const DenseTensor& x, \
|
||||
const DenseTensor& dout, \
|
||||
double attr, \
|
||||
DenseTensor* dx) { \
|
||||
funcs::functor_class<T> functor; \
|
||||
auto attrs = functor.GetAttrs(); \
|
||||
*(attrs[0].second) = attr; \
|
||||
ActivationGradGPUImpl<T, Context, funcs::functor_class<T>>( \
|
||||
dev_ctx, &x, nullptr, &dout, dx, functor); \
|
||||
}
|
||||
|
||||
#define DEFINE_GPU_ACT_GRAD_KERNEL_WITH_TWO_ATTRS_DEPX( \
|
||||
name, functor_class, attr1, attr2) \
|
||||
template <typename T, typename Context> \
|
||||
void name##GradKernel(const Context& dev_ctx, \
|
||||
const DenseTensor& x, \
|
||||
const DenseTensor& dout, \
|
||||
float attr1, \
|
||||
float attr2, \
|
||||
DenseTensor* dx) { \
|
||||
funcs::functor_class<T> functor; \
|
||||
auto attrs = functor.GetAttrs(); \
|
||||
*(attrs[0].second) = attr1; \
|
||||
*(attrs[1].second) = attr2; \
|
||||
ActivationGradGPUImpl<T, Context, funcs::functor_class<T>>( \
|
||||
dev_ctx, &x, nullptr, &dout, dx, functor); \
|
||||
}
|
||||
|
||||
#define DEFINE_GPU_ACT_GRAD_KERNEL_WITH_TWO_DOUBLE_ATTRS_DEPX( \
|
||||
name, functor_class, attr1, attr2) \
|
||||
template <typename T, typename Context> \
|
||||
void name##GradKernel(const Context& dev_ctx, \
|
||||
const DenseTensor& x, \
|
||||
const DenseTensor& dout, \
|
||||
double attr1, \
|
||||
double attr2, \
|
||||
DenseTensor* dx) { \
|
||||
funcs::functor_class<T> functor; \
|
||||
auto attrs = functor.GetAttrs(); \
|
||||
*(attrs[0].second) = attr1; \
|
||||
*(attrs[1].second) = attr2; \
|
||||
ActivationGradGPUImpl<T, Context, funcs::functor_class<T>>( \
|
||||
dev_ctx, &x, nullptr, &dout, dx, functor); \
|
||||
}
|
||||
|
||||
#define DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPOUT(name, functor_class) \
|
||||
template <typename T, typename Context> \
|
||||
void name##GradKernel(const Context& dev_ctx, \
|
||||
const DenseTensor& out, \
|
||||
const DenseTensor& dout, \
|
||||
DenseTensor* dx) { \
|
||||
funcs::functor_class<T> functor; \
|
||||
ActivationGradGPUImpl<T, Context, funcs::functor_class<T>>( \
|
||||
dev_ctx, nullptr, &out, &dout, dx, functor); \
|
||||
}
|
||||
|
||||
#define DEFINE_GPU_ACT_GRAD_KERNEL_WITH_ONE_ATTRS_DEPOUT( \
|
||||
name, functor_class, attr) \
|
||||
template <typename T, typename Context> \
|
||||
void name##GradKernel(const Context& dev_ctx, \
|
||||
const DenseTensor& out, \
|
||||
const DenseTensor& dout, \
|
||||
float attr, \
|
||||
DenseTensor* dx) { \
|
||||
funcs::functor_class<T> functor; \
|
||||
auto attrs = functor.GetAttrs(); \
|
||||
*(attrs[0].second) = attr; \
|
||||
ActivationGradGPUImpl<T, Context, funcs::functor_class<T>>( \
|
||||
dev_ctx, nullptr, &out, &dout, dx, functor); \
|
||||
}
|
||||
|
||||
#define DEFINE_GPU_ACT_GRAD_KERNEL_WITH_ONE_DOUBLE_ATTRS_DEPOUT( \
|
||||
name, functor_class, attr) \
|
||||
template <typename T, typename Context> \
|
||||
void name##GradKernel(const Context& dev_ctx, \
|
||||
const DenseTensor& out, \
|
||||
const DenseTensor& dout, \
|
||||
double attr, \
|
||||
DenseTensor* dx) { \
|
||||
funcs::functor_class<T> functor; \
|
||||
auto attrs = functor.GetAttrs(); \
|
||||
*(attrs[0].second) = attr; \
|
||||
ActivationGradGPUImpl<T, Context, funcs::functor_class<T>>( \
|
||||
dev_ctx, nullptr, &out, &dout, dx, functor); \
|
||||
}
|
||||
|
||||
#define DEFINE_GPU_ACT_GRAD_KERNEL_WITH_TWO_ATTRS_DEPOUT( \
|
||||
name, functor_class, attr1, attr2) \
|
||||
template <typename T, typename Context> \
|
||||
void name##GradKernel(const Context& dev_ctx, \
|
||||
const DenseTensor& out, \
|
||||
const DenseTensor& dout, \
|
||||
float attr1, \
|
||||
float attr2, \
|
||||
DenseTensor* dx) { \
|
||||
funcs::functor_class<T> functor; \
|
||||
auto attrs = functor.GetAttrs(); \
|
||||
*(attrs[0].second) = attr1; \
|
||||
*(attrs[1].second) = attr2; \
|
||||
ActivationGradGPUImpl<T, Context, funcs::functor_class<T>>( \
|
||||
dev_ctx, nullptr, &out, &dout, dx, functor); \
|
||||
}
|
||||
|
||||
#define DEFINE_GPU_ACTIVATION_GRAD_KERNEL_NODEP(name, functor_class) \
|
||||
template <typename T, typename Context> \
|
||||
void name##GradKernel( \
|
||||
const Context& dev_ctx, const DenseTensor& dout, DenseTensor* dx) { \
|
||||
funcs::functor_class<T> functor; \
|
||||
ActivationGradGPUImpl<T, Context, funcs::functor_class<T>>( \
|
||||
dev_ctx, nullptr, nullptr, &dout, dx, functor); \
|
||||
}
|
||||
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPOUT(Relu, CudaReluGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPOUT(Tanh, CudaTanhGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPOUT(Sigmoid, CudaSigmoidGradFunctor);
|
||||
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_NODEP(Rint, CudaZeroGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_NODEP(Round, CudaZeroGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_NODEP(Floor, CudaZeroGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_NODEP(Ceil, CudaZeroGradFunctor);
|
||||
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Cos, CudaCosGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Tan, CudaTanGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Acos, CudaAcosGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Sin, CudaSinGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Asin, CudaAsinGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Atan, CudaAtanGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Sinh, CudaSinhGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Cosh, CudaCoshGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Asinh, CudaAsinhGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Acosh, CudaAcoshGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Atanh, CudaAtanhGradFunctor);
|
||||
// TanhShrinkGrad: custom kernel to support FLAGS_use_accuracy_compatible_kernel
|
||||
template <typename T, typename Context>
|
||||
void TanhShrinkGradKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const DenseTensor& dout,
|
||||
DenseTensor* dx) {
|
||||
funcs::CudaTanhShrinkGradFunctor<T> functor;
|
||||
functor.compatible = FLAGS_use_accuracy_compatible_kernel;
|
||||
ActivationGradGPUImpl<T, Context, funcs::CudaTanhShrinkGradFunctor<T>>(
|
||||
dev_ctx, &x, nullptr, &dout, dx, functor);
|
||||
}
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Square, CudaSquareGradFunctor);
|
||||
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPOUT(Exp, CudaExpGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPOUT(Expm1, CudaExpm1GradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPOUT(Reciprocal, CudaReciprocalGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPOUT(Sqrt, CudaSqrtGradFunctor);
|
||||
// RsqrtGrad: custom kernel to support FLAGS_use_accuracy_compatible_kernel
|
||||
template <typename T, typename Context>
|
||||
void RsqrtGradKernel(const Context& dev_ctx,
|
||||
const DenseTensor& out,
|
||||
const DenseTensor& dout,
|
||||
DenseTensor* dx) {
|
||||
if (FLAGS_use_accuracy_compatible_kernel) {
|
||||
funcs::CudaRsqrtGradFunctor<T, true> functor;
|
||||
ActivationGradGPUImpl<T, Context, funcs::CudaRsqrtGradFunctor<T, true>>(
|
||||
dev_ctx, nullptr, &out, &dout, dx, functor);
|
||||
} else {
|
||||
funcs::CudaRsqrtGradFunctor<T, false> functor;
|
||||
ActivationGradGPUImpl<T, Context, funcs::CudaRsqrtGradFunctor<T, false>>(
|
||||
dev_ctx, nullptr, &out, &dout, dx, functor);
|
||||
}
|
||||
}
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPOUT(Relu6, CudaRelu6GradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Softsign, CudaSoftsignGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(LogSigmoid, CudaLogSigmoidGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Log, CudaLogGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Log2, CudaLog2GradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Log10, CudaLog10GradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Log1p, CudaLog1pGradFunctor);
|
||||
DEFINE_GPU_ACTIVATION_GRAD_KERNEL_DEPX(Swish, CudaSwishGradFunctor);
|
||||
|
||||
DEFINE_GPU_ACT_GRAD_KERNEL_WITH_ONE_DOUBLE_ATTRS_DEPX(LeakyRelu,
|
||||
CudaLeakyReluGradFunctor,
|
||||
alpha);
|
||||
DEFINE_GPU_ACT_GRAD_KERNEL_WITH_ONE_ATTRS_DEPX(SoftShrink,
|
||||
CudaSoftShrinkGradFunctor,
|
||||
lambda);
|
||||
DEFINE_GPU_ACT_GRAD_KERNEL_WITH_ONE_ATTRS_DEPX(HardShrink,
|
||||
CudaHardShrinkGradFunctor,
|
||||
threshold);
|
||||
|
||||
DEFINE_GPU_ACT_GRAD_KERNEL_WITH_ONE_ATTRS_DEPX(Mish,
|
||||
CudaMishGradFunctor,
|
||||
threshold);
|
||||
DEFINE_GPU_ACT_GRAD_KERNEL_WITH_ONE_ATTRS_DEPX(Celu,
|
||||
CudaCELUGradFunctor,
|
||||
alpha);
|
||||
DEFINE_GPU_ACT_GRAD_KERNEL_WITH_ONE_DOUBLE_ATTRS_DEPOUT(LogitCUDA,
|
||||
CudaLogitGradFunctor,
|
||||
eps);
|
||||
|
||||
DEFINE_GPU_ACT_GRAD_KERNEL_WITH_TWO_ATTRS_DEPX(HardTanh,
|
||||
CudaHardTanhGradFunctor,
|
||||
t_min,
|
||||
t_max);
|
||||
|
||||
DEFINE_GPU_ACT_GRAD_KERNEL_WITH_TWO_ATTRS_DEPX(STanh,
|
||||
CudaSTanhGradFunctor,
|
||||
scale_a,
|
||||
scale_b);
|
||||
|
||||
DEFINE_GPU_ACT_GRAD_KERNEL_WITH_TWO_DOUBLE_ATTRS_DEPX(Softplus,
|
||||
CudaSoftplusGradFunctor,
|
||||
beta,
|
||||
threshold);
|
||||
DEFINE_GPU_ACT_GRAD_KERNEL_WITH_TWO_ATTRS_DEPOUT(HardSigmoid,
|
||||
CudaHardSigmoidGradFunctor,
|
||||
slope,
|
||||
offset);
|
||||
DEFINE_GPU_ACT_GRAD_KERNEL_WITH_TWO_ATTRS_DEPX(ThresholdedRelu,
|
||||
CudaThresholdedReluGradFunctor,
|
||||
threshold,
|
||||
value);
|
||||
|
||||
template <typename T, typename Context>
|
||||
void SiluGradKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const DenseTensor& out,
|
||||
const DenseTensor& dout,
|
||||
DenseTensor* dx) {
|
||||
funcs::CudaSiluGradFunctor<T> functor;
|
||||
ActivationGradGPUImpl<T, Context, funcs::CudaSiluGradFunctor<T>>(
|
||||
dev_ctx, &x, &out, &dout, dx, functor);
|
||||
}
|
||||
template <typename T, typename Context>
|
||||
void EluGradKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const DenseTensor& out,
|
||||
const DenseTensor& dout,
|
||||
float alpha,
|
||||
DenseTensor* dx) {
|
||||
dev_ctx.template Alloc<T>(dx);
|
||||
if (dx->numel() == 0) {
|
||||
return;
|
||||
}
|
||||
std::vector<const DenseTensor*> ins = {&dout, &out};
|
||||
std::vector<DenseTensor*> outs = {dx};
|
||||
if (alpha > 0) {
|
||||
funcs::CudaELUGradFunctor<T> functor;
|
||||
functor.alpha = alpha;
|
||||
funcs::ElementwiseKernel<T>(dev_ctx, ins, &outs, functor);
|
||||
} else {
|
||||
funcs::CudaELUGradNegativeAlphaFunctor<T> functor;
|
||||
functor.alpha = alpha;
|
||||
ins.push_back(&x);
|
||||
funcs::ElementwiseKernel<T>(dev_ctx, ins, &outs, functor);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void HardSwishGradKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const DenseTensor& dout,
|
||||
DenseTensor* dx) {
|
||||
funcs::CudaHardSwishGradFunctor<T> functor;
|
||||
float threshold = 6;
|
||||
float scale = 6;
|
||||
float offset = 3;
|
||||
auto attrs = functor.GetAttrs();
|
||||
*(attrs[0].second) = threshold;
|
||||
*(attrs[1].second) = scale;
|
||||
*(attrs[2].second) = offset;
|
||||
ActivationGradGPUImpl<T, Context, funcs::CudaHardSwishGradFunctor<T>>(
|
||||
dev_ctx, &x, nullptr, &dout, dx, functor);
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void PowGradKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const DenseTensor& dout,
|
||||
const Scalar& factor,
|
||||
DenseTensor* dx) {
|
||||
if (factor.to<double>() == 0) {
|
||||
std::vector<int64_t> vec_dims = vectorize(dx->dims());
|
||||
Full<T, Context>(dev_ctx, IntArray(vec_dims), static_cast<T>(0), dx);
|
||||
return;
|
||||
}
|
||||
if (factor.to<double>() == 1) {
|
||||
std::vector<int64_t> vec_dims = vectorize(dx->dims());
|
||||
Copy<Context>(dev_ctx, dout, dev_ctx.GetPlace(), false, dx);
|
||||
return;
|
||||
}
|
||||
if (factor.to<double>() == 2) {
|
||||
funcs::CudaSquareGradFunctor<T> functor;
|
||||
ActivationGradGPUImpl<T, Context, funcs::CudaSquareGradFunctor<T>>(
|
||||
dev_ctx, &x, nullptr, &dout, dx, functor);
|
||||
return;
|
||||
}
|
||||
if (factor.to<double>() == 3) {
|
||||
funcs::CudaCubeGradFunctor<T> functor;
|
||||
ActivationGradGPUImpl<T, Context, funcs::CudaCubeGradFunctor<T>>(
|
||||
dev_ctx, &x, nullptr, &dout, dx, functor);
|
||||
return;
|
||||
}
|
||||
if (factor.to<double>() == 4) {
|
||||
funcs::CudaPow4GradFunctor<T> functor;
|
||||
ActivationGradGPUImpl<T, Context, funcs::CudaPow4GradFunctor<T>>(
|
||||
dev_ctx, &x, nullptr, &dout, dx, functor);
|
||||
return;
|
||||
}
|
||||
if constexpr (!std::is_integral<T>::value) {
|
||||
if (factor.to<double>() == 1.5) {
|
||||
funcs::CudaPow1p5GradFunctor<T> functor;
|
||||
ActivationGradGPUImpl<T, Context, funcs::CudaPow1p5GradFunctor<T>>(
|
||||
dev_ctx, &x, nullptr, &dout, dx, functor);
|
||||
return;
|
||||
}
|
||||
if (factor.to<double>() == 0.5) {
|
||||
funcs::CudaSqrtGradDepXFunctor<T> functor;
|
||||
ActivationGradGPUImpl<T, Context, funcs::CudaSqrtGradDepXFunctor<T>>(
|
||||
dev_ctx, &x, nullptr, &dout, dx, functor);
|
||||
return;
|
||||
}
|
||||
if (factor.to<double>() == -1) {
|
||||
funcs::CudaReciprocalGradDepXFunctor<T> functor;
|
||||
ActivationGradGPUImpl<T,
|
||||
Context,
|
||||
funcs::CudaReciprocalGradDepXFunctor<T>>(
|
||||
dev_ctx, &x, nullptr, &dout, dx, functor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
funcs::CudaPowGradFunctor<T> functor;
|
||||
functor.SetFactor(factor.to<double>());
|
||||
ActivationGradGPUImpl<T, Context, funcs::CudaPowGradFunctor<T>>(
|
||||
dev_ctx, &x, nullptr, &dout, dx, functor);
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
PD_REGISTER_KERNEL(relu_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ReluGradKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16) {}
|
||||
PD_REGISTER_KERNEL(relu_double_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ReluDoubleGradKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16) {}
|
||||
#else
|
||||
PD_REGISTER_KERNEL(relu_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ReluGradKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
PD_REGISTER_KERNEL(relu_double_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ReluDoubleGradKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
#endif
|
||||
|
||||
#define PD_REGISTER_ACTIVATION_GRAD_KERNEL(name, func) \
|
||||
PD_REGISTER_KERNEL(name, \
|
||||
GPU, \
|
||||
ALL_LAYOUT, \
|
||||
phi::func, \
|
||||
float, \
|
||||
double, \
|
||||
phi::float16, \
|
||||
phi::bfloat16) {}
|
||||
|
||||
#define PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(name, func) \
|
||||
PD_REGISTER_KERNEL(name, \
|
||||
GPU, \
|
||||
ALL_LAYOUT, \
|
||||
phi::func, \
|
||||
float, \
|
||||
double, \
|
||||
phi::float16, \
|
||||
phi::bfloat16, \
|
||||
phi::complex64, \
|
||||
phi::complex128) {}
|
||||
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(sin_grad, SinGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(cos_grad, CosGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(tan_grad, TanGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(acos_grad, AcosGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(asin_grad, AsinGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(atan_grad, AtanGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(sinh_grad, SinhGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(cosh_grad, CoshGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(asinh_grad, AsinhGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(acosh_grad, AcoshGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(atanh_grad, AtanhGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(tanh_grad, TanhGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(tanh_double_grad,
|
||||
TanhDoubleGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(tanh_triple_grad,
|
||||
TanhTripleGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(hardtanh_grad, HardTanhGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(leaky_relu_grad, LeakyReluGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(leaky_relu_double_grad,
|
||||
LeakyReluDoubleGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(thresholded_relu_grad,
|
||||
ThresholdedReluGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(relu6_grad, Relu6GradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(mish_grad, MishGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(stanh_grad, STanhGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(reciprocal_grad,
|
||||
ReciprocalGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(softplus_grad,
|
||||
SoftplusGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(softplus_double_grad,
|
||||
SoftplusDoubleGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(sqrt_grad, SqrtGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(sqrt_double_grad, SqrtDoubleGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(rsqrt_grad, RsqrtGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(rsqrt_double_grad, RsqrtDoubleGradKernel)
|
||||
|
||||
PD_REGISTER_KERNEL(exp_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ExpGradKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(softshrink_grad, SoftShrinkGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(hard_shrink_grad, HardShrinkGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(tanh_shrink_grad, TanhShrinkGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(silu_grad, SiluGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(elu_grad, EluGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(elu_double_grad, EluDoubleGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(logit_grad, LogitCUDAGradKernel)
|
||||
|
||||
PD_REGISTER_KERNEL(expm1_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::Expm1GradKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
|
||||
PD_REGISTER_KERNEL(square_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::SquareGradKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
PD_REGISTER_KERNEL(square_double_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::SquareDoubleGradKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
|
||||
PD_REGISTER_KERNEL(sin_double_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::SinDoubleGradKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
|
||||
PD_REGISTER_KERNEL(sin_triple_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::SinTripleGradKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
|
||||
PD_REGISTER_KERNEL(cos_double_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CosDoubleGradKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
|
||||
PD_REGISTER_KERNEL(cos_triple_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CosTripleGradKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(softsign_grad,
|
||||
SoftsignGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(sigmoid_grad, SigmoidGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(sigmoid_double_grad,
|
||||
SigmoidDoubleGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(sigmoid_triple_grad,
|
||||
SigmoidTripleGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(hardsigmoid_grad, HardSigmoidGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(logsigmoid_grad,
|
||||
LogSigmoidGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(log_grad, LogGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(log2_grad, Log2GradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(log10_grad, Log10GradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(log1p_grad, Log1pGradKernel)
|
||||
PD_REGISTER_KERNEL(log_double_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::LogDoubleGradKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL_WITH_COMPLEX(hardswish_grad,
|
||||
HardSwishGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(swish_grad, SwishGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(celu_grad, CeluGradKernel)
|
||||
PD_REGISTER_ACTIVATION_GRAD_KERNEL(celu_double_grad, CeluDoubleGradKernel)
|
||||
|
||||
PD_REGISTER_KERNEL(rint_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::RintGradKernel,
|
||||
int,
|
||||
int64_t,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
PD_REGISTER_KERNEL(round_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::RoundGradKernel,
|
||||
int,
|
||||
int64_t,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
PD_REGISTER_KERNEL(pow_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::PowGradKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
PD_REGISTER_KERNEL(pow_double_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::PowDoubleGradKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
PD_REGISTER_KERNEL(pow_triple_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::PowTripleGradKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
PD_REGISTER_KERNEL(ceil_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CeilGradKernel,
|
||||
float,
|
||||
double,
|
||||
uint8_t,
|
||||
int8_t,
|
||||
int16_t,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
PD_REGISTER_KERNEL(floor_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::FloorGradKernel,
|
||||
float,
|
||||
double,
|
||||
uint8_t,
|
||||
int8_t,
|
||||
int16_t,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,532 @@
|
||||
/* Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. */
|
||||
|
||||
#include "paddle/phi/kernels/activation_kernel.h"
|
||||
#include "paddle/common/flags.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_device_function.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/full_kernel.h"
|
||||
#include "paddle/phi/kernels/funcs/elementwise_base.h"
|
||||
#include "paddle/phi/kernels/impl/activation_grad_impl.h"
|
||||
#include "paddle/phi/kernels/impl/activation_impl.h"
|
||||
|
||||
COMMON_DECLARE_bool(use_accuracy_compatible_kernel);
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context, typename Functor>
|
||||
void ActivationGPUImpl(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
DenseTensor* out,
|
||||
const Functor& functor) {
|
||||
PADDLE_ENFORCE_NOT_NULL(out,
|
||||
errors::NotFound("Output Out should not be nullptr"));
|
||||
dev_ctx.template Alloc<T>(out);
|
||||
if (out->numel() == 0) {
|
||||
return;
|
||||
}
|
||||
std::vector<const DenseTensor*> ins = {&x};
|
||||
std::vector<DenseTensor*> outs = {out};
|
||||
funcs::ElementwiseKernel<T>(dev_ctx, ins, &outs, functor);
|
||||
}
|
||||
|
||||
#define DEFINE_GPU_ACTIVATION_KERNEL(name, functor_class) \
|
||||
template <typename T, typename Context> \
|
||||
void name##Kernel( \
|
||||
const Context& dev_ctx, const DenseTensor& x, DenseTensor* out) { \
|
||||
funcs::functor_class<T> functor; \
|
||||
ActivationGPUImpl<T, Context, funcs::functor_class<T>>( \
|
||||
dev_ctx, x, out, functor); \
|
||||
}
|
||||
|
||||
#define DEFINE_GPU_ACTIVATION_KERNEL_WITH_INT_IN_FLOAT_OUT(name, \
|
||||
functor_class) \
|
||||
template <typename T, typename Context> \
|
||||
void name##Kernel( \
|
||||
const Context& dev_ctx, const DenseTensor& x, DenseTensor* out) { \
|
||||
funcs::functor_class<T> functor; \
|
||||
using U = \
|
||||
typename std::conditional_t<std::is_integral<T>::value, float, T>; \
|
||||
ActivationGPUImpl<U, Context, funcs::functor_class<T>>( \
|
||||
dev_ctx, x, out, functor); \
|
||||
}
|
||||
|
||||
#define DEFINE_GPU_ACT_KERNEL_WITH_ONE_ATTRS(name, functor_class, attr) \
|
||||
template <typename T, typename Context> \
|
||||
void name##Kernel(const Context& dev_ctx, \
|
||||
const DenseTensor& x, \
|
||||
float attr, \
|
||||
DenseTensor* out) { \
|
||||
funcs::functor_class<T> functor; \
|
||||
auto attrs = functor.GetAttrs(); \
|
||||
*(attrs[0].second) = attr; \
|
||||
ActivationGPUImpl<T, Context, funcs::functor_class<T>>( \
|
||||
dev_ctx, x, out, functor); \
|
||||
}
|
||||
|
||||
#define DEFINE_GPU_ACT_KERNEL_WITH_ONE_DOUBLE_ATTRS(name, functor_class, attr) \
|
||||
template <typename T, typename Context> \
|
||||
void name##Kernel(const Context& dev_ctx, \
|
||||
const DenseTensor& x, \
|
||||
double attr, \
|
||||
DenseTensor* out) { \
|
||||
funcs::functor_class<T> functor; \
|
||||
auto attrs = functor.GetAttrs(); \
|
||||
*(attrs[0].second) = attr; \
|
||||
ActivationGPUImpl<T, Context, funcs::functor_class<T>>( \
|
||||
dev_ctx, x, out, functor); \
|
||||
}
|
||||
|
||||
#define DEFINE_GPU_ACT_KERNEL_WITH_TWO_ATTRS( \
|
||||
name, functor_class, attr1, attr2) \
|
||||
template <typename T, typename Context> \
|
||||
void name##Kernel(const Context& dev_ctx, \
|
||||
const DenseTensor& x, \
|
||||
float attr1, \
|
||||
float attr2, \
|
||||
DenseTensor* out) { \
|
||||
funcs::functor_class<T> functor; \
|
||||
auto attrs = functor.GetAttrs(); \
|
||||
*(attrs[0].second) = attr1; \
|
||||
*(attrs[1].second) = attr2; \
|
||||
ActivationGPUImpl<T, Context, funcs::functor_class<T>>( \
|
||||
dev_ctx, x, out, functor); \
|
||||
}
|
||||
|
||||
#define DEFINE_GPU_ACT_KERNEL_WITH_TWO_DOUBLE_ATTRS( \
|
||||
name, functor_class, attr1, attr2) \
|
||||
template <typename T, typename Context> \
|
||||
void name##Kernel(const Context& dev_ctx, \
|
||||
const DenseTensor& x, \
|
||||
double attr1, \
|
||||
double attr2, \
|
||||
DenseTensor* out) { \
|
||||
funcs::functor_class<T> functor; \
|
||||
auto attrs = functor.GetAttrs(); \
|
||||
*(attrs[0].second) = attr1; \
|
||||
*(attrs[1].second) = attr2; \
|
||||
ActivationGPUImpl<T, Context, funcs::functor_class<T>>( \
|
||||
dev_ctx, x, out, functor); \
|
||||
}
|
||||
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Cos, CudaCosFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Tan, CudaTanFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Acos, CudaAcosFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Sin, CudaSinFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Asin, CudaAsinFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Atan, CudaAtanFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Sinh, CudaSinhFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Cosh, CudaCoshFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Asinh, CudaAsinhFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Acosh, CudaAcoshFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Atanh, CudaAtanhFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Relu, CudaReluFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Tanh, CudaTanhFunctor)
|
||||
// TanhShrink: custom kernel to support FLAGS_use_accuracy_compatible_kernel
|
||||
template <typename T, typename Context>
|
||||
void TanhShrinkKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
DenseTensor* out) {
|
||||
funcs::CudaTanhShrinkFunctor<T> functor;
|
||||
functor.compatible = FLAGS_use_accuracy_compatible_kernel;
|
||||
ActivationGPUImpl<T, Context, funcs::CudaTanhShrinkFunctor<T>>(
|
||||
dev_ctx, x, out, functor);
|
||||
}
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Silu, CudaSiluFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Reciprocal, CudaReciprocalFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Square, CudaSquareFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Sqrt, CudaSqrtFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Rsqrt, CudaRsqrtFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Softsign, CudaSoftsignFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Sigmoid, CudaSigmoidFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(LogSigmoid, CudaLogSigmoidFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Floor, CudaFloorFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Ceil, CudaCeilFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL(Rint, CudaRintFunctor)
|
||||
|
||||
DEFINE_GPU_ACTIVATION_KERNEL_WITH_INT_IN_FLOAT_OUT(Log, CudaLogFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL_WITH_INT_IN_FLOAT_OUT(Log2, CudaLog2Functor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL_WITH_INT_IN_FLOAT_OUT(Log10, CudaLog10Functor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL_WITH_INT_IN_FLOAT_OUT(Log1p, CudaLog1pFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL_WITH_INT_IN_FLOAT_OUT(Exp, CudaExpFunctor)
|
||||
DEFINE_GPU_ACTIVATION_KERNEL_WITH_INT_IN_FLOAT_OUT(Expm1, CudaExpm1Functor)
|
||||
|
||||
DEFINE_GPU_ACT_KERNEL_WITH_ONE_DOUBLE_ATTRS(LeakyRelu,
|
||||
CudaLeakyReluFunctor,
|
||||
alpha)
|
||||
DEFINE_GPU_ACT_KERNEL_WITH_ONE_DOUBLE_ATTRS(LogitCUDA, CudaLogitFunctor, eps)
|
||||
DEFINE_GPU_ACT_KERNEL_WITH_ONE_ATTRS(HardShrink,
|
||||
CudaHardShrinkFunctor,
|
||||
threshold)
|
||||
DEFINE_GPU_ACT_KERNEL_WITH_ONE_ATTRS(SoftShrink, CudaSoftShrinkFunctor, lambda)
|
||||
DEFINE_GPU_ACT_KERNEL_WITH_ONE_ATTRS(Elu, CudaELUFunctor, alpha)
|
||||
DEFINE_GPU_ACT_KERNEL_WITH_ONE_ATTRS(Mish, CudaMishFunctor, threshold)
|
||||
DEFINE_GPU_ACT_KERNEL_WITH_ONE_ATTRS(Celu, CudaCELUFunctor, alpha)
|
||||
|
||||
DEFINE_GPU_ACT_KERNEL_WITH_TWO_ATTRS(HardTanh,
|
||||
CudaHardTanhFunctor,
|
||||
t_min,
|
||||
t_max)
|
||||
DEFINE_GPU_ACT_KERNEL_WITH_TWO_ATTRS(Stanh, CudaSTanhFunctor, scale_a, scale_b)
|
||||
DEFINE_GPU_ACT_KERNEL_WITH_TWO_DOUBLE_ATTRS(Softplus,
|
||||
CudaSoftplusFunctor,
|
||||
beta,
|
||||
threshold)
|
||||
DEFINE_GPU_ACT_KERNEL_WITH_TWO_ATTRS(HardSigmoid,
|
||||
CudaHardSigmoidFunctor,
|
||||
slope,
|
||||
offset)
|
||||
DEFINE_GPU_ACT_KERNEL_WITH_TWO_ATTRS(Selu, CudaSeluFunctor, scale, alpha)
|
||||
DEFINE_GPU_ACT_KERNEL_WITH_TWO_ATTRS(ThresholdedRelu,
|
||||
CudaThresholdedReluFunctor,
|
||||
threshold,
|
||||
value)
|
||||
|
||||
template <typename T, typename Context>
|
||||
void HardSwishKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
DenseTensor* out) {
|
||||
funcs::CudaHardSwishFunctor<T> functor;
|
||||
float threshold = 6;
|
||||
float scale = 6;
|
||||
float offset = 3;
|
||||
auto attrs = functor.GetAttrs();
|
||||
*(attrs[0].second) = threshold;
|
||||
*(attrs[1].second) = scale;
|
||||
*(attrs[2].second) = offset;
|
||||
ActivationGPUImpl<T, Context, funcs::CudaHardSwishFunctor<T>>(
|
||||
dev_ctx, x, out, functor);
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void SwishKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
DenseTensor* out) {
|
||||
funcs::CudaSwishFunctor<T> functor;
|
||||
auto attrs = functor.GetAttrs();
|
||||
*(attrs[0].second) = 1.0;
|
||||
ActivationGPUImpl<T, Context, funcs::CudaSwishFunctor<T>>(
|
||||
dev_ctx, x, out, functor);
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void Relu6Kernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
DenseTensor* out) {
|
||||
funcs::CudaRelu6Functor<T> functor;
|
||||
auto attrs = functor.GetAttrs();
|
||||
*(attrs[0].second) = 6.0;
|
||||
ActivationGPUImpl<T, Context, funcs::CudaRelu6Functor<T>>(
|
||||
dev_ctx, x, out, functor);
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void RoundKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const int decimals,
|
||||
DenseTensor* out) {
|
||||
funcs::CudaRoundFunctor<T> functor;
|
||||
auto attrs = functor.GetAttrs();
|
||||
*(attrs[0].second) = decimals;
|
||||
ActivationGPUImpl<T, Context, funcs::CudaRoundFunctor<T>>(
|
||||
dev_ctx, x, out, functor);
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void PowKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const Scalar& factor,
|
||||
DenseTensor* out) {
|
||||
if constexpr (std::is_integral<T>::value) {
|
||||
PADDLE_ENFORCE_GE(
|
||||
factor.to<double>(),
|
||||
0,
|
||||
common::errors::InvalidArgument(
|
||||
"Integers to negative integer powers are not allowed."));
|
||||
} else {
|
||||
if (factor.to<double>() == 0.5) {
|
||||
funcs::CudaSqrtFunctor<T> functor;
|
||||
ActivationGPUImpl<T, Context, funcs::CudaSqrtFunctor<T>>(
|
||||
dev_ctx, x, out, functor);
|
||||
return;
|
||||
}
|
||||
if (factor.to<double>() == -0.5) {
|
||||
funcs::CudaRsqrtFunctor<T> functor;
|
||||
ActivationGPUImpl<T, Context, funcs::CudaRsqrtFunctor<T>>(
|
||||
dev_ctx, x, out, functor);
|
||||
return;
|
||||
}
|
||||
if (factor.to<double>() == -1) {
|
||||
funcs::CudaReciprocalFunctor<T> functor;
|
||||
ActivationGPUImpl<T, Context, funcs::CudaReciprocalFunctor<T>>(
|
||||
dev_ctx, x, out, functor);
|
||||
return;
|
||||
}
|
||||
if (factor.to<double>() == -2) {
|
||||
funcs::CudaRsquareFunctor<T> functor;
|
||||
ActivationGPUImpl<T, Context, funcs::CudaRsquareFunctor<T>>(
|
||||
dev_ctx, x, out, functor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (factor.to<double>() == 0) {
|
||||
std::vector<int64_t> vec_dims = vectorize(out->dims());
|
||||
Full<T, Context>(dev_ctx, IntArray(vec_dims), static_cast<T>(1), out);
|
||||
return;
|
||||
}
|
||||
if (factor.to<double>() == 1) {
|
||||
Copy<Context>(dev_ctx, x, dev_ctx.GetPlace(), false, out);
|
||||
return;
|
||||
}
|
||||
if (factor.to<double>() == 2) {
|
||||
funcs::CudaSquareFunctor<T> functor;
|
||||
ActivationGPUImpl<T, Context, funcs::CudaSquareFunctor<T>>(
|
||||
dev_ctx, x, out, functor);
|
||||
return;
|
||||
}
|
||||
if (factor.to<double>() == 3) {
|
||||
funcs::CudaCubeFunctor<T> functor;
|
||||
ActivationGPUImpl<T, Context, funcs::CudaCubeFunctor<T>>(
|
||||
dev_ctx, x, out, functor);
|
||||
return;
|
||||
}
|
||||
|
||||
funcs::CudaPowFunctor<T> functor;
|
||||
functor.SetFactor(factor.to<double>());
|
||||
ActivationGPUImpl<T, Context, funcs::CudaPowFunctor<T>>(
|
||||
dev_ctx, x, out, functor);
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
PD_REGISTER_KERNEL(
|
||||
relu, GPU, ALL_LAYOUT, phi::ReluKernel, float, double, phi::float16) {}
|
||||
#else
|
||||
PD_REGISTER_KERNEL(relu,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ReluKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
#endif
|
||||
|
||||
#define PD_REGISTER_ACTIVATION_KERNEL(name, func) \
|
||||
PD_REGISTER_KERNEL(name, \
|
||||
GPU, \
|
||||
ALL_LAYOUT, \
|
||||
phi::func, \
|
||||
float, \
|
||||
double, \
|
||||
phi::float16, \
|
||||
phi::bfloat16) {}
|
||||
|
||||
#define PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(name, func) \
|
||||
PD_REGISTER_KERNEL(name, \
|
||||
GPU, \
|
||||
ALL_LAYOUT, \
|
||||
phi::func, \
|
||||
float, \
|
||||
double, \
|
||||
phi::float16, \
|
||||
phi::bfloat16, \
|
||||
phi::complex64, \
|
||||
phi::complex128) {}
|
||||
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(sin, SinKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(cos, CosKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(tan, TanKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(acos, AcosKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(asin, AsinKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(atan, AtanKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(sinh, SinhKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(cosh, CoshKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(asinh, AsinhKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(acosh, AcoshKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(atanh, AtanhKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(tanh, TanhKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL(hardtanh, HardTanhKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL(thresholded_relu, ThresholdedReluKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL(relu6, Relu6Kernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL(leaky_relu, LeakyReluKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL(mish, MishKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(stanh, StanhKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(reciprocal, ReciprocalKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(sqrt, SqrtKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL(rsqrt, RsqrtKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(softplus, SoftplusKernel)
|
||||
|
||||
PD_REGISTER_KERNEL(exp,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ExpKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
PD_REGISTER_KERNEL(expm1,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::Expm1Kernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
PD_REGISTER_KERNEL(square,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::SquareKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
|
||||
PD_REGISTER_ACTIVATION_KERNEL(hard_shrink, HardShrinkKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL(softshrink, SoftShrinkKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL(tanh_shrink, TanhShrinkKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL(elu, EluKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(silu, SiluKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(softsign, SoftsignKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(sigmoid, SigmoidKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(logsigmoid, LogSigmoidKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL(hardsigmoid, HardSigmoidKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL_WITH_COMPLEX(hardswish, HardSwishKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL(swish, SwishKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL(celu, CeluKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL(selu, SeluKernel)
|
||||
PD_REGISTER_ACTIVATION_KERNEL(logit, LogitCUDAKernel)
|
||||
|
||||
PD_REGISTER_KERNEL(rint,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::RintKernel,
|
||||
int,
|
||||
int64_t,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
PD_REGISTER_KERNEL(round,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::RoundKernel,
|
||||
int,
|
||||
int64_t,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
PD_REGISTER_KERNEL(log,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::LogKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
PD_REGISTER_KERNEL(log2,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::Log2Kernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
PD_REGISTER_KERNEL(log10,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::Log10Kernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
PD_REGISTER_KERNEL(log1p,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::Log1pKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
PD_REGISTER_KERNEL(pow,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::PowKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
PD_REGISTER_KERNEL(ceil,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CeilKernel,
|
||||
float,
|
||||
double,
|
||||
uint8_t,
|
||||
int8_t,
|
||||
int16_t,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
PD_REGISTER_KERNEL(floor,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::FloorKernel,
|
||||
float,
|
||||
double,
|
||||
uint8_t,
|
||||
int8_t,
|
||||
int16_t,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/adadelta_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/adadelta_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(adadelta,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AdadeltaKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16) {
|
||||
if (kernel_key.dtype() == phi::DataType::FLOAT16) {
|
||||
kernel->OutputAt(1).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(2).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(3).SetDataType(phi::DataType::FLOAT32);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/adagrad_kernel.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_launch_config.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/math_function.h"
|
||||
#include "paddle/phi/kernels/funcs/selected_rows_functor.h"
|
||||
#include "paddle/phi/kernels/impl/adagrad_kernel_impl.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename MT>
|
||||
__global__ void AdagradGPUKernel(const T* param,
|
||||
const T* grad,
|
||||
const MT* moment,
|
||||
const MT* lr,
|
||||
const MT* master_param,
|
||||
MT epsilon,
|
||||
T* param_out,
|
||||
MT* moment_out,
|
||||
MT* master_param_out,
|
||||
int64_t num) {
|
||||
int64_t idx =
|
||||
static_cast<int64_t>(blockDim.x) * static_cast<int64_t>(blockIdx.x) +
|
||||
static_cast<int64_t>(threadIdx.x);
|
||||
MT lr_data = static_cast<MT>(lr[0]);
|
||||
|
||||
for (int64_t i = idx; i < num; i += blockDim.x * gridDim.x) {
|
||||
MT grad_data = static_cast<MT>(grad[i]);
|
||||
MT moment_out_data = static_cast<MT>(moment[i]) + grad_data * grad_data;
|
||||
moment_out[i] = static_cast<MT>(moment_out_data);
|
||||
auto in = master_param_out ? master_param[i] : static_cast<MT>(param[i]);
|
||||
MT param_out_data =
|
||||
in - (lr_data * grad_data) / (sqrt(moment_out_data) + epsilon);
|
||||
|
||||
param_out[i] = static_cast<T>(param_out_data);
|
||||
|
||||
if (master_param_out) {
|
||||
master_param_out[i] = param_out_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct DenseAdagradFunctor<GPUContext, T> {
|
||||
void operator()(const GPUContext& dev_ctx,
|
||||
const DenseTensor& param_t,
|
||||
const DenseTensor& grad_t,
|
||||
const DenseTensor& moment_t,
|
||||
const DenseTensor& learning_rate,
|
||||
const optional<DenseTensor>& master_param,
|
||||
float epsilon_t,
|
||||
bool multi_precision,
|
||||
DenseTensor* param_out_tensor,
|
||||
DenseTensor* moment_out_tensor,
|
||||
DenseTensor* master_param_outs) {
|
||||
using MT = typename dtype::template MPTypeTrait<T>::Type;
|
||||
T* param_out_data = dev_ctx.template Alloc<T>(param_out_tensor);
|
||||
MT* moment_out_data = dev_ctx.template Alloc<MT>(moment_out_tensor);
|
||||
const MT* master_in_data =
|
||||
multi_precision ? master_param->data<MT>() : nullptr;
|
||||
MT* master_out_data = multi_precision
|
||||
? dev_ctx.template Alloc<MT>(master_param_outs)
|
||||
: nullptr;
|
||||
|
||||
MT epsilon = static_cast<MT>(epsilon_t);
|
||||
|
||||
int64_t numel = param_t.numel();
|
||||
auto config = backends::gpu::GetGpuLaunchConfig1D(dev_ctx, numel, 1);
|
||||
int grid = config.block_per_grid.x;
|
||||
int block = config.thread_per_block.x;
|
||||
auto stream = dev_ctx.stream();
|
||||
AdagradGPUKernel<T, MT>
|
||||
<<<block, grid, 0, stream>>>(param_t.data<T>(),
|
||||
grad_t.data<T>(),
|
||||
moment_t.data<MT>(),
|
||||
learning_rate.data<MT>(),
|
||||
master_in_data,
|
||||
epsilon,
|
||||
param_out_data,
|
||||
moment_out_data,
|
||||
master_out_data,
|
||||
numel);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, int block_size>
|
||||
__global__ void MergeGradKernel(const T* grad,
|
||||
const int64_t* grad_rows,
|
||||
T* grad_merge,
|
||||
const int64_t* grad_merge_rows,
|
||||
size_t grad_merge_rows_size,
|
||||
int64_t row_numel) {
|
||||
const int ty = blockIdx.y;
|
||||
int tid = threadIdx.x;
|
||||
__shared__ size_t grad_merge_idx;
|
||||
|
||||
if (tid == 0) {
|
||||
for (size_t i = 0; i < grad_merge_rows_size; i++) {
|
||||
if (grad_rows[ty] == grad_merge_rows[i]) {
|
||||
grad_merge_idx = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__syncthreads();
|
||||
|
||||
grad += ty * row_numel;
|
||||
grad_merge += grad_merge_idx * row_numel;
|
||||
for (int64_t index = tid; index < row_numel; index += block_size) {
|
||||
CudaAtomicAdd(grad_merge + index, grad[index]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, int block_size>
|
||||
__global__ void SparseAdagradFunctorKernel(const T* grad,
|
||||
const int64_t* rows,
|
||||
const T* learning_rate,
|
||||
T* param,
|
||||
T* moment,
|
||||
int64_t row_numel,
|
||||
T epsilon) {
|
||||
const int ty = blockIdx.y;
|
||||
int tid = threadIdx.x;
|
||||
|
||||
grad += ty * row_numel;
|
||||
param += rows[ty] * row_numel;
|
||||
moment += rows[ty] * row_numel;
|
||||
|
||||
for (int64_t index = tid; index < row_numel; index += block_size) {
|
||||
// Since index in rows of SelectedRows can be duplicate, we have to use
|
||||
// Atomic Operation to avoid concurrent write error.
|
||||
CudaAtomicAdd(param + index,
|
||||
-1.0 * learning_rate[0] * grad[index] /
|
||||
(sqrt(moment[index]) + epsilon));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct SparseAdagradFunctor<GPUContext, T> {
|
||||
void operator()(const GPUContext& dev_ctx,
|
||||
const SelectedRows& grad,
|
||||
const DenseTensor& learning_rate,
|
||||
T epsilon,
|
||||
DenseTensor* moment,
|
||||
DenseTensor* param) {
|
||||
// 1. g_m.rows = set(g.rows)
|
||||
auto grad_width = grad.value().dims()[1];
|
||||
funcs::scatter::MergeAdd<GPUContext, T> merge_func;
|
||||
auto grad_merge = merge_func(dev_ctx, grad);
|
||||
auto* grad_merge_data = grad_merge.mutable_value()->template data<T>();
|
||||
Vector<int64_t> merge_rows(grad_merge.rows());
|
||||
// 2. m += g_m * g_m
|
||||
auto grad_square = SquareSelectedRows<GPUContext, T>(dev_ctx, grad_merge);
|
||||
|
||||
funcs::SelectedRowsAddToTensor<GPUContext, T> functor;
|
||||
functor(dev_ctx, grad_square, moment);
|
||||
|
||||
// 3. update parameter
|
||||
auto* lr = learning_rate.data<T>();
|
||||
auto* param_data = param->data<T>();
|
||||
auto* moment_data = moment->data<T>();
|
||||
|
||||
const int block_size = 256;
|
||||
dim3 threads(block_size, 1);
|
||||
dim3 grid2(1, merge_rows.size());
|
||||
MixVector<int64_t> mixv_merge_rows(&merge_rows);
|
||||
SparseAdagradFunctorKernel<T, 256>
|
||||
<<<grid2,
|
||||
threads,
|
||||
0,
|
||||
reinterpret_cast<const GPUContext&>(dev_ctx).stream()>>>(
|
||||
grad_merge_data,
|
||||
mixv_merge_rows.CUDAMutableData(dev_ctx.GetPlace()),
|
||||
lr,
|
||||
param_data,
|
||||
moment_data,
|
||||
grad_width,
|
||||
epsilon);
|
||||
mixv_merge_rows.CopyToCPU();
|
||||
}
|
||||
};
|
||||
|
||||
template struct SparseAdagradFunctor<GPUContext, float>;
|
||||
template struct SparseAdagradFunctor<GPUContext, double>;
|
||||
template struct DenseAdagradFunctor<GPUContext, float>;
|
||||
template struct DenseAdagradFunctor<GPUContext, double>;
|
||||
template struct DenseAdagradFunctor<GPUContext, float16>;
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(adagrad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AdagradDenseKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16) {
|
||||
if (kernel_key.dtype() == phi::DataType::FLOAT16) {
|
||||
kernel->OutputAt(1).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(2).SetDataType(phi::DataType::FLOAT32);
|
||||
}
|
||||
}
|
||||
|
||||
PD_REGISTER_KERNEL(adagrad_dense_param_sparse_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AdagradSparseKernel,
|
||||
float,
|
||||
double) {}
|
||||
@@ -0,0 +1,991 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/adam_kernel.h"
|
||||
|
||||
#include <math.h> // for sqrt in CPU and CUDA
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "glog/logging.h"
|
||||
#include "paddle/common/flags.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/core/tensor_utils.h"
|
||||
#include "paddle/phi/kernels/funcs/adam_functors.h"
|
||||
#include "paddle/phi/kernels/funcs/for_range.h"
|
||||
|
||||
COMMON_DECLARE_bool(use_accuracy_compatible_kernel);
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename TG, typename MT>
|
||||
__global__ void AdamKernelREG(MT beta1,
|
||||
MT beta2,
|
||||
MT epsilon,
|
||||
MT beta1_pow_,
|
||||
MT beta2_pow_,
|
||||
const MT* moment1,
|
||||
MT* moment1_out,
|
||||
const MT* moment2,
|
||||
MT* moment2_out,
|
||||
const MT* moment2_max,
|
||||
MT* moment2_max_out,
|
||||
const double* lr_,
|
||||
const TG* grad,
|
||||
const T* param,
|
||||
T* param_out,
|
||||
const MT* master_param,
|
||||
MT* master_param_out,
|
||||
int64_t ndim,
|
||||
bool amsgrad) {
|
||||
MT lr = static_cast<MT>(*lr_);
|
||||
MT beta1_pow = beta1_pow_;
|
||||
MT beta2_pow = beta2_pow_;
|
||||
|
||||
int64_t id =
|
||||
static_cast<int64_t>(blockIdx.x) * static_cast<int64_t>(blockDim.x) +
|
||||
static_cast<int64_t>(threadIdx.x);
|
||||
|
||||
for (; id < ndim; id += gridDim.x * blockDim.x) {
|
||||
MT p = master_param ? master_param[id] : static_cast<MT>(param[id]);
|
||||
MT g = static_cast<MT>(grad[id]);
|
||||
MT mom1 = static_cast<MT>(moment1[id]);
|
||||
MT mom2 = static_cast<MT>(moment2[id]);
|
||||
|
||||
mom1 = beta1 * mom1 + (static_cast<MT>(1.0) - beta1) * g;
|
||||
mom2 = beta2 * mom2 + (static_cast<MT>(1.0) - beta2) * g * g;
|
||||
|
||||
MT denom;
|
||||
if (amsgrad) {
|
||||
MT mom2_max = static_cast<MT>(moment2_max[id]);
|
||||
MT mom2_max_ = std::max(mom2, mom2_max);
|
||||
moment2_max_out[id] = mom2_max_;
|
||||
|
||||
denom =
|
||||
(sqrt(mom2_max_) / sqrt(static_cast<MT>(1.0) - beta2_pow)) + epsilon;
|
||||
} else {
|
||||
denom = (sqrt(mom2) / sqrt(static_cast<MT>(1.0) - beta2_pow)) + epsilon;
|
||||
}
|
||||
|
||||
p += (mom1 / denom) * (-(lr / (static_cast<MT>(1.0) - beta1_pow)));
|
||||
|
||||
moment1_out[id] = mom1;
|
||||
moment2_out[id] = mom2;
|
||||
param_out[id] = static_cast<T>(p);
|
||||
if (master_param_out) {
|
||||
master_param_out[id] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename TG, typename MT>
|
||||
__global__ void AdamKernelMEM(MT beta1,
|
||||
MT beta2,
|
||||
MT epsilon,
|
||||
const MT* beta1_pow_,
|
||||
const MT* beta2_pow_,
|
||||
const MT* moment1,
|
||||
MT* moment1_out,
|
||||
const MT* moment2,
|
||||
MT* moment2_out,
|
||||
const MT* moment2_max,
|
||||
MT* moment2_max_out,
|
||||
const double* lr_,
|
||||
const TG* grad,
|
||||
const T* param,
|
||||
T* param_out,
|
||||
const MT* master_param,
|
||||
MT* master_param_out,
|
||||
int64_t ndim,
|
||||
bool amsgrad) {
|
||||
MT lr = static_cast<MT>(*lr_);
|
||||
MT beta1_pow = *beta1_pow_;
|
||||
MT beta2_pow = *beta2_pow_;
|
||||
|
||||
int64_t id =
|
||||
static_cast<int64_t>(blockIdx.x) * static_cast<int64_t>(blockDim.x) +
|
||||
static_cast<int64_t>(threadIdx.x);
|
||||
|
||||
for (; id < ndim; id += gridDim.x * blockDim.x) {
|
||||
MT p = master_param ? master_param[id] : static_cast<MT>(param[id]);
|
||||
MT g = static_cast<MT>(grad[id]);
|
||||
MT mom1 = static_cast<MT>(moment1[id]);
|
||||
MT mom2 = static_cast<MT>(moment2[id]);
|
||||
|
||||
mom1 = beta1 * mom1 + (static_cast<MT>(1.0) - beta1) * g;
|
||||
mom2 = beta2 * mom2 + (static_cast<MT>(1.0) - beta2) * g * g;
|
||||
|
||||
MT denom;
|
||||
if (amsgrad) {
|
||||
MT mom2_max = static_cast<MT>(moment2_max[id]);
|
||||
MT mom2_max_ = std::max(mom2, mom2_max);
|
||||
moment2_max_out[id] = mom2_max_;
|
||||
|
||||
denom =
|
||||
(sqrt(mom2_max_) / sqrt(static_cast<MT>(1.0) - beta2_pow)) + epsilon;
|
||||
} else {
|
||||
denom = (sqrt(mom2) / sqrt(static_cast<MT>(1.0) - beta2_pow)) + epsilon;
|
||||
}
|
||||
|
||||
p += (mom1 / denom) * (-(lr / (static_cast<MT>(1.0) - beta1_pow)));
|
||||
|
||||
moment1_out[id] = mom1;
|
||||
moment2_out[id] = mom2;
|
||||
param_out[id] = static_cast<T>(p);
|
||||
if (master_param_out) {
|
||||
master_param_out[id] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void UpdateBetaPow(T beta1,
|
||||
T beta2,
|
||||
const T* beta1_pow_,
|
||||
const T* beta2_pow_,
|
||||
T* beta1_pow_out,
|
||||
T* beta2_pow_out) {
|
||||
*beta1_pow_out = beta1 * beta1_pow_[0];
|
||||
*beta2_pow_out = beta2 * beta2_pow_[0];
|
||||
}
|
||||
|
||||
// ---- Torch-compatible Adam infrastructure ----
|
||||
|
||||
// LrAccessor for Adam: lr tensor is MT (float), upcast to double on device.
|
||||
template <typename MT, bool IsCpu>
|
||||
struct AdamLrAccessor;
|
||||
|
||||
template <typename MT>
|
||||
struct AdamLrAccessor<MT, true> {
|
||||
const double lr_double;
|
||||
explicit AdamLrAccessor(double lr) : lr_double(lr) {}
|
||||
__device__ __forceinline__ double GetLrDouble() const { return lr_double; }
|
||||
};
|
||||
|
||||
template <typename MT>
|
||||
struct AdamLrAccessor<MT, false> {
|
||||
const double* lr;
|
||||
explicit AdamLrAccessor(const double* lr) : lr(lr) {}
|
||||
__device__ __forceinline__ double GetLrDouble() const { return *lr; }
|
||||
};
|
||||
|
||||
// Bias correction accessors matching torch's step_count-based computation.
|
||||
template <typename MT, bool IsCpu>
|
||||
struct AdamBiasCorrAccessorCompat;
|
||||
|
||||
template <typename MT>
|
||||
struct AdamBiasCorrAccessorCompat<MT, true> {
|
||||
const double beta1;
|
||||
const double beta2;
|
||||
const float step_count;
|
||||
|
||||
AdamBiasCorrAccessorCompat(double b1, double b2, float sc)
|
||||
: beta1(b1), beta2(b2), step_count(sc) {}
|
||||
|
||||
__device__ __forceinline__ double GetBc1() const {
|
||||
return 1.0 - ::pow(beta1, step_count);
|
||||
}
|
||||
__device__ __forceinline__ double GetBc2() const {
|
||||
return 1.0 - ::pow(beta2, step_count);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename MT>
|
||||
struct AdamBiasCorrAccessorCompat<MT, false> {
|
||||
const double beta1;
|
||||
const double beta2;
|
||||
const MT* beta1_pow;
|
||||
|
||||
AdamBiasCorrAccessorCompat(double b1, double b2, const MT* bp1)
|
||||
: beta1(b1), beta2(b2), beta1_pow(bp1) {}
|
||||
|
||||
__device__ __forceinline__ double GetBc1() const {
|
||||
const float sc = static_cast<float>(
|
||||
::round(::log(static_cast<double>(*beta1_pow)) / ::log(beta1)));
|
||||
return 1.0 - ::pow(beta1, sc);
|
||||
}
|
||||
__device__ __forceinline__ double GetBc2() const {
|
||||
const float sc = static_cast<float>(
|
||||
::round(::log(static_cast<double>(*beta1_pow)) / ::log(beta1)));
|
||||
return 1.0 - ::pow(beta2, sc);
|
||||
}
|
||||
};
|
||||
|
||||
// Torch-compatible Adam kernel: no weight decay, float lr upcast to double,
|
||||
// FMA-based moment updates matching torch's fused adam math.
|
||||
template <typename T,
|
||||
typename TG,
|
||||
typename MT,
|
||||
typename LrAccessor,
|
||||
typename BiasCorrAccessor>
|
||||
__global__ void AdamStyleKernel(const double beta1,
|
||||
const double beta2,
|
||||
const double epsilon,
|
||||
LrAccessor lr_accessor,
|
||||
BiasCorrAccessor bias_corr_accessor,
|
||||
const TG* __restrict__ grad,
|
||||
const T* __restrict__ param,
|
||||
T* __restrict__ param_out,
|
||||
const MT* __restrict__ master_param,
|
||||
MT* __restrict__ master_param_out,
|
||||
const MT* __restrict__ moment1,
|
||||
MT* __restrict__ moment1_out,
|
||||
const MT* __restrict__ moment2,
|
||||
MT* __restrict__ moment2_out,
|
||||
const MT* __restrict__ moment2_max,
|
||||
MT* __restrict__ moment2_max_out,
|
||||
int64_t ndim,
|
||||
bool amsgrad) {
|
||||
__shared__ double one_minus_beta1_shared;
|
||||
__shared__ double one_minus_beta2_shared;
|
||||
__shared__ MT bias_correction2_sqrt_shared;
|
||||
__shared__ MT step_size_shared;
|
||||
|
||||
if (threadIdx.x == 0) {
|
||||
const double lr_double = lr_accessor.GetLrDouble();
|
||||
const double bc1_dbl = bias_corr_accessor.GetBc1();
|
||||
const double bc2_dbl = bias_corr_accessor.GetBc2();
|
||||
const double bc2_sqrt_dbl = ::sqrt(bc2_dbl);
|
||||
|
||||
one_minus_beta1_shared = 1.0 - beta1;
|
||||
one_minus_beta2_shared = 1.0 - beta2;
|
||||
const MT bias_correction1 = static_cast<MT>(bc1_dbl);
|
||||
bias_correction2_sqrt_shared = static_cast<MT>(bc2_sqrt_dbl);
|
||||
step_size_shared = lr_double / bias_correction1;
|
||||
}
|
||||
__syncthreads();
|
||||
|
||||
const double one_minus_beta1 = one_minus_beta1_shared;
|
||||
const double one_minus_beta2 = one_minus_beta2_shared;
|
||||
const MT bias_correction2_sqrt = bias_correction2_sqrt_shared;
|
||||
const MT step_size = step_size_shared;
|
||||
|
||||
int64_t id =
|
||||
static_cast<int64_t>(blockIdx.x) * static_cast<int64_t>(blockDim.x) +
|
||||
static_cast<int64_t>(threadIdx.x);
|
||||
|
||||
for (; id < ndim; id += static_cast<int64_t>(gridDim.x) *
|
||||
static_cast<int64_t>(blockDim.x)) {
|
||||
MT p = master_param ? master_param[id] : static_cast<MT>(param[id]);
|
||||
MT g = static_cast<MT>(grad[id]);
|
||||
MT exp_avg = static_cast<MT>(moment1[id]);
|
||||
MT exp_avg_sq = static_cast<MT>(moment2[id]);
|
||||
const double g_d = static_cast<double>(g);
|
||||
|
||||
// exp_avg = beta1 * exp_avg + (1 - beta1) * grad
|
||||
// FMA variant A: compute (1-beta1)*grad first, then fma(beta1, exp_avg,
|
||||
// t2). This matches NVCC's fused adam: beta1*exp_avg computed exactly in
|
||||
// FMA.
|
||||
{
|
||||
const double exp_avg_d = static_cast<double>(exp_avg);
|
||||
const double t2 = __dmul_rn(one_minus_beta1, g_d);
|
||||
exp_avg = static_cast<MT>(__fma_rn(beta1, exp_avg_d, t2));
|
||||
}
|
||||
|
||||
// exp_avg_sq = beta2 * exp_avg_sq + (1 - beta2) * grad^2
|
||||
// Left-to-right: ((1-beta2)*g)*g, then separate add, matching PyTorch.
|
||||
{
|
||||
const double exp_avg_sq_d = static_cast<double>(exp_avg_sq);
|
||||
const double t1 = __dmul_rn(beta2, exp_avg_sq_d);
|
||||
const double t2 = __dmul_rn(one_minus_beta2, g_d);
|
||||
const double t3 = __dmul_rn(t2, g_d);
|
||||
exp_avg_sq = static_cast<MT>(__dadd_rn(t1, t3));
|
||||
}
|
||||
|
||||
MT denom;
|
||||
if (amsgrad) {
|
||||
MT max_exp_avg_sq = static_cast<MT>(moment2_max[id]);
|
||||
max_exp_avg_sq =
|
||||
max_exp_avg_sq > exp_avg_sq ? max_exp_avg_sq : exp_avg_sq;
|
||||
moment2_max_out[id] = max_exp_avg_sq;
|
||||
denom = (sqrt(max_exp_avg_sq) / bias_correction2_sqrt) + epsilon;
|
||||
} else {
|
||||
denom = (sqrt(exp_avg_sq) / bias_correction2_sqrt) + epsilon;
|
||||
}
|
||||
|
||||
p -= step_size * exp_avg / denom;
|
||||
|
||||
moment1_out[id] = exp_avg;
|
||||
moment2_out[id] = exp_avg_sq;
|
||||
param_out[id] = static_cast<T>(p);
|
||||
if (master_param_out) {
|
||||
master_param_out[id] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AdamDenseKernel_compatible(const Context& dev_ctx,
|
||||
const DenseTensor& param,
|
||||
const DenseTensor& grad,
|
||||
const DenseTensor& learning_rate,
|
||||
const DenseTensor& moment1,
|
||||
const DenseTensor& moment2,
|
||||
const optional<DenseTensor>& moment2_max,
|
||||
const DenseTensor& beta1_pow,
|
||||
const DenseTensor& beta2_pow,
|
||||
const optional<DenseTensor>& master_param,
|
||||
const optional<DenseTensor>& skip_update,
|
||||
const Scalar& beta1,
|
||||
const Scalar& beta2,
|
||||
const Scalar& epsilon,
|
||||
bool lazy_mode,
|
||||
int64_t min_row_size_to_use_multithread,
|
||||
bool multi_precision,
|
||||
bool use_global_beta_pow,
|
||||
bool amsgrad,
|
||||
DenseTensor* param_out,
|
||||
DenseTensor* moment1_out,
|
||||
DenseTensor* moment2_out,
|
||||
DenseTensor* moment2_max_out,
|
||||
DenseTensor* beta1_pow_out,
|
||||
DenseTensor* beta2_pow_out,
|
||||
DenseTensor* master_param_outs) {
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
|
||||
bool skip_update_ = false;
|
||||
if (skip_update.is_initialized()) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
skip_update->numel(),
|
||||
1,
|
||||
errors::InvalidArgument("Input(SkipUpdate) size must be 1, but get %d",
|
||||
skip_update->numel()));
|
||||
std::vector<bool> skip_update_vec;
|
||||
TensorToVector(*skip_update, dev_ctx, &skip_update_vec);
|
||||
skip_update_ = skip_update_vec[0];
|
||||
}
|
||||
|
||||
if (skip_update_) {
|
||||
VLOG(4) << "Adam skip update";
|
||||
Copy(dev_ctx, param, dev_ctx.GetPlace(), false, param_out);
|
||||
Copy(dev_ctx, moment1, dev_ctx.GetPlace(), false, moment1_out);
|
||||
Copy(dev_ctx, moment2, dev_ctx.GetPlace(), false, moment2_out);
|
||||
if (amsgrad) {
|
||||
Copy(dev_ctx,
|
||||
moment2_max.get(),
|
||||
dev_ctx.GetPlace(),
|
||||
false,
|
||||
moment2_max_out);
|
||||
}
|
||||
if (!use_global_beta_pow) {
|
||||
Copy(dev_ctx, beta1_pow, beta1_pow.place(), false, beta1_pow_out);
|
||||
Copy(dev_ctx, beta2_pow, beta2_pow.place(), false, beta2_pow_out);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
double beta1_ = beta1.to<double>();
|
||||
double beta2_ = beta2.to<double>();
|
||||
double epsilon_ = epsilon.to<double>();
|
||||
|
||||
PADDLE_ENFORCE_EQ(
|
||||
beta1_pow_out->numel(),
|
||||
1,
|
||||
errors::InvalidArgument("beta1 pow output size should be 1, but received "
|
||||
"value is:%d.",
|
||||
beta1_pow_out->numel()));
|
||||
PADDLE_ENFORCE_EQ(
|
||||
beta2_pow_out->numel(),
|
||||
1,
|
||||
errors::InvalidArgument("beta2 pow output size should be 1, but received "
|
||||
"value is:%d.",
|
||||
beta2_pow_out->numel()));
|
||||
|
||||
const bool beta_pow_on_cpu =
|
||||
beta1_pow.place() == CPUPlace() && beta2_pow.place() == CPUPlace();
|
||||
const bool lr_on_cpu = learning_rate.place() == CPUPlace();
|
||||
|
||||
// Read float lr on host if available; on device it's read in kernel.
|
||||
double lr_host_double = 0.0;
|
||||
if (lr_on_cpu) {
|
||||
lr_host_double = learning_rate.data<double>()[0];
|
||||
}
|
||||
|
||||
const MT* master_in_data =
|
||||
multi_precision ? master_param->data<MT>() : nullptr;
|
||||
MT* master_out_data =
|
||||
multi_precision ? dev_ctx.template Alloc<MT>(master_param_outs) : nullptr;
|
||||
|
||||
const MT* moment2_max_in_data =
|
||||
amsgrad ? moment2_max.get().data<MT>() : nullptr;
|
||||
MT* moment2_max_out_data =
|
||||
amsgrad ? dev_ctx.template Alloc<MT>(moment2_max_out) : nullptr;
|
||||
|
||||
int threads = 512;
|
||||
int64_t blocks_max = dev_ctx.GetCUDAMaxGridDimSize()[0];
|
||||
int blocks = std::min((param.numel() + threads - 1) / threads, blocks_max);
|
||||
|
||||
const bool use_float32_grad = grad.dtype() == DataType::FLOAT32;
|
||||
|
||||
// Use decltype so template args are inferred from the local accessor variables.
|
||||
#define LAUNCH_ADAM_STYLE_KERNEL() \
|
||||
if (use_float32_grad) { \
|
||||
AdamStyleKernel<T, \
|
||||
float, \
|
||||
MT, \
|
||||
decltype(lr_accessor), \
|
||||
decltype(bias_corr_accessor)> \
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>( \
|
||||
beta1_, \
|
||||
beta2_, \
|
||||
epsilon_, \
|
||||
lr_accessor, \
|
||||
bias_corr_accessor, \
|
||||
grad.data<float>(), \
|
||||
param.data<T>(), \
|
||||
dev_ctx.template Alloc<T>(param_out), \
|
||||
master_in_data, \
|
||||
master_out_data, \
|
||||
moment1.data<MT>(), \
|
||||
dev_ctx.template Alloc<MT>(moment1_out), \
|
||||
moment2.data<MT>(), \
|
||||
dev_ctx.template Alloc<MT>(moment2_out), \
|
||||
moment2_max_in_data, \
|
||||
moment2_max_out_data, \
|
||||
param.numel(), \
|
||||
amsgrad); \
|
||||
} else { \
|
||||
AdamStyleKernel<T, \
|
||||
T, \
|
||||
MT, \
|
||||
decltype(lr_accessor), \
|
||||
decltype(bias_corr_accessor)> \
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>( \
|
||||
beta1_, \
|
||||
beta2_, \
|
||||
epsilon_, \
|
||||
lr_accessor, \
|
||||
bias_corr_accessor, \
|
||||
grad.data<T>(), \
|
||||
param.data<T>(), \
|
||||
dev_ctx.template Alloc<T>(param_out), \
|
||||
master_in_data, \
|
||||
master_out_data, \
|
||||
moment1.data<MT>(), \
|
||||
dev_ctx.template Alloc<MT>(moment1_out), \
|
||||
moment2.data<MT>(), \
|
||||
dev_ctx.template Alloc<MT>(moment2_out), \
|
||||
moment2_max_in_data, \
|
||||
moment2_max_out_data, \
|
||||
param.numel(), \
|
||||
amsgrad); \
|
||||
}
|
||||
|
||||
if (lr_on_cpu) {
|
||||
AdamLrAccessor<MT, true> lr_accessor(lr_host_double);
|
||||
if (beta_pow_on_cpu) {
|
||||
const float sc = static_cast<float>(
|
||||
std::round(std::log(static_cast<double>(beta1_pow.data<MT>()[0])) /
|
||||
std::log(beta1_)));
|
||||
AdamBiasCorrAccessorCompat<MT, true> bias_corr_accessor(
|
||||
beta1_, beta2_, sc);
|
||||
LAUNCH_ADAM_STYLE_KERNEL()
|
||||
} else {
|
||||
AdamBiasCorrAccessorCompat<MT, false> bias_corr_accessor(
|
||||
beta1_, beta2_, beta1_pow.data<MT>());
|
||||
LAUNCH_ADAM_STYLE_KERNEL()
|
||||
}
|
||||
} else {
|
||||
AdamLrAccessor<MT, false> lr_accessor(learning_rate.data<double>());
|
||||
if (beta_pow_on_cpu) {
|
||||
const float sc = static_cast<float>(
|
||||
std::round(std::log(static_cast<double>(beta1_pow.data<MT>()[0])) /
|
||||
std::log(beta1_)));
|
||||
AdamBiasCorrAccessorCompat<MT, true> bias_corr_accessor(
|
||||
beta1_, beta2_, sc);
|
||||
LAUNCH_ADAM_STYLE_KERNEL()
|
||||
} else {
|
||||
AdamBiasCorrAccessorCompat<MT, false> bias_corr_accessor(
|
||||
beta1_, beta2_, beta1_pow.data<MT>());
|
||||
LAUNCH_ADAM_STYLE_KERNEL()
|
||||
}
|
||||
}
|
||||
#undef LAUNCH_ADAM_STYLE_KERNEL
|
||||
|
||||
if (!use_global_beta_pow) {
|
||||
if (beta_pow_on_cpu) {
|
||||
dev_ctx.template HostAlloc<MT>(beta1_pow_out)[0] =
|
||||
static_cast<MT>(beta1_) * beta1_pow.data<MT>()[0];
|
||||
dev_ctx.template HostAlloc<MT>(beta2_pow_out)[0] =
|
||||
static_cast<MT>(beta2_) * beta2_pow.data<MT>()[0];
|
||||
} else {
|
||||
UpdateBetaPow<MT><<<1, 1, 0, dev_ctx.stream()>>>(
|
||||
static_cast<MT>(beta1_),
|
||||
static_cast<MT>(beta2_),
|
||||
beta1_pow.data<MT>(),
|
||||
beta2_pow.data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(beta1_pow_out),
|
||||
dev_ctx.template Alloc<MT>(beta2_pow_out));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
PADDLE_API void AdamDenseKernel(const Context& dev_ctx,
|
||||
const DenseTensor& param,
|
||||
const DenseTensor& grad,
|
||||
const DenseTensor& learning_rate,
|
||||
const DenseTensor& moment1,
|
||||
const DenseTensor& moment2,
|
||||
const optional<DenseTensor>& moment2_max,
|
||||
const DenseTensor& beta1_pow,
|
||||
const DenseTensor& beta2_pow,
|
||||
const optional<DenseTensor>& master_param,
|
||||
const optional<DenseTensor>& skip_update,
|
||||
const Scalar& beta1,
|
||||
const Scalar& beta2,
|
||||
const Scalar& epsilon,
|
||||
bool lazy_mode,
|
||||
int64_t min_row_size_to_use_multithread,
|
||||
bool multi_precision,
|
||||
bool use_global_beta_pow,
|
||||
bool amsgrad,
|
||||
DenseTensor* param_out,
|
||||
DenseTensor* moment1_out,
|
||||
DenseTensor* moment2_out,
|
||||
DenseTensor* moment2_max_out,
|
||||
DenseTensor* beta1_pow_out,
|
||||
DenseTensor* beta2_pow_out,
|
||||
DenseTensor* master_param_outs) {
|
||||
if (FLAGS_use_accuracy_compatible_kernel) {
|
||||
AdamDenseKernel_compatible<T, Context>(dev_ctx,
|
||||
param,
|
||||
grad,
|
||||
learning_rate,
|
||||
moment1,
|
||||
moment2,
|
||||
moment2_max,
|
||||
beta1_pow,
|
||||
beta2_pow,
|
||||
master_param,
|
||||
skip_update,
|
||||
beta1,
|
||||
beta2,
|
||||
epsilon,
|
||||
lazy_mode,
|
||||
min_row_size_to_use_multithread,
|
||||
multi_precision,
|
||||
use_global_beta_pow,
|
||||
amsgrad,
|
||||
param_out,
|
||||
moment1_out,
|
||||
moment2_out,
|
||||
moment2_max_out,
|
||||
beta1_pow_out,
|
||||
beta2_pow_out,
|
||||
master_param_outs);
|
||||
return;
|
||||
}
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
const auto grad_type = grad.dtype();
|
||||
|
||||
VLOG(4) << "use_global_beta_pow:" << use_global_beta_pow;
|
||||
VLOG(4) << "amsgrad: " << amsgrad;
|
||||
|
||||
bool skip_update_ = false;
|
||||
if (skip_update.is_initialized()) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
skip_update->numel(),
|
||||
1,
|
||||
errors::InvalidArgument("Input(SkipUpdate) size must be 1, but get %d",
|
||||
skip_update->numel()));
|
||||
std::vector<bool> skip_update_vec;
|
||||
TensorToVector(*skip_update, dev_ctx, &skip_update_vec);
|
||||
skip_update_ = skip_update_vec[0];
|
||||
}
|
||||
// skip_update=true, just copy input to output, and TensorCopy will call
|
||||
// mutable_data
|
||||
if (skip_update_) {
|
||||
VLOG(4) << "Adam skip update";
|
||||
Copy(dev_ctx, param, dev_ctx.GetPlace(), false, param_out);
|
||||
Copy(dev_ctx, moment1, dev_ctx.GetPlace(), false, moment1_out);
|
||||
Copy(dev_ctx, moment2, dev_ctx.GetPlace(), false, moment2_out);
|
||||
if (amsgrad) {
|
||||
Copy(dev_ctx,
|
||||
moment2_max.get(),
|
||||
dev_ctx.GetPlace(),
|
||||
false,
|
||||
moment2_max_out);
|
||||
}
|
||||
if (!use_global_beta_pow) {
|
||||
Copy(dev_ctx, beta1_pow, beta1_pow.place(), false, beta1_pow_out);
|
||||
Copy(dev_ctx, beta2_pow, beta2_pow.place(), false, beta2_pow_out);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
MT beta1_ = beta1.to<MT>();
|
||||
MT beta2_ = beta2.to<MT>();
|
||||
MT epsilon_ = epsilon.to<MT>();
|
||||
VLOG(3) << "beta1_pow.numel() : " << beta1_pow.numel()
|
||||
<< "beta2_pow.numel() : " << beta2_pow.numel();
|
||||
VLOG(3) << "param.numel(): " << param.numel();
|
||||
PADDLE_ENFORCE_EQ(
|
||||
beta1_pow_out->numel(),
|
||||
1,
|
||||
errors::InvalidArgument("beta1 pow output size should be 1, but received "
|
||||
"value is:%d.",
|
||||
beta1_pow_out->numel()));
|
||||
|
||||
PADDLE_ENFORCE_EQ(
|
||||
beta2_pow_out->numel(),
|
||||
1,
|
||||
errors::InvalidArgument("beta2 pow output size should be 1, but received "
|
||||
"value is:%d.",
|
||||
beta2_pow_out->numel()));
|
||||
|
||||
const MT* master_in_data =
|
||||
multi_precision ? master_param->data<MT>() : nullptr;
|
||||
MT* master_out_data =
|
||||
multi_precision ? dev_ctx.template Alloc<MT>(master_param_outs) : nullptr;
|
||||
|
||||
const MT* moment2_max_in_data =
|
||||
amsgrad ? moment2_max.get().data<MT>() : nullptr;
|
||||
MT* moment2_max_out_data =
|
||||
amsgrad ? dev_ctx.template Alloc<MT>(moment2_max_out) : nullptr;
|
||||
|
||||
// update param and moment
|
||||
int threads = 512;
|
||||
int64_t blocks_max = dev_ctx.GetCUDAMaxGridDimSize()[0];
|
||||
int blocks = std::min((param.numel() + threads - 1) / threads, blocks_max);
|
||||
|
||||
if (beta1_pow.place() == CPUPlace() && beta2_pow.place() == CPUPlace()) {
|
||||
// Compute with betapow in REG
|
||||
if (grad_type == DataType::FLOAT32) {
|
||||
AdamKernelREG<T, float, MT><<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
beta1_,
|
||||
beta2_,
|
||||
epsilon_,
|
||||
*beta1_pow.data<MT>(),
|
||||
*beta2_pow.data<MT>(),
|
||||
moment1.data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(moment1_out),
|
||||
moment2.data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(moment2_out),
|
||||
moment2_max_in_data,
|
||||
moment2_max_out_data,
|
||||
learning_rate.data<double>(),
|
||||
grad.data<float>(),
|
||||
param.data<T>(),
|
||||
dev_ctx.template Alloc<T>(param_out),
|
||||
master_in_data,
|
||||
master_out_data,
|
||||
param.numel(),
|
||||
amsgrad);
|
||||
} else {
|
||||
AdamKernelREG<T, T, MT><<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
beta1_,
|
||||
beta2_,
|
||||
epsilon_,
|
||||
*beta1_pow.data<MT>(),
|
||||
*beta2_pow.data<MT>(),
|
||||
moment1.data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(moment1_out),
|
||||
moment2.data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(moment2_out),
|
||||
moment2_max_in_data,
|
||||
moment2_max_out_data,
|
||||
learning_rate.data<double>(),
|
||||
grad.data<T>(),
|
||||
param.data<T>(),
|
||||
dev_ctx.template Alloc<T>(param_out),
|
||||
master_in_data,
|
||||
master_out_data,
|
||||
param.numel(),
|
||||
amsgrad);
|
||||
}
|
||||
if (!use_global_beta_pow) {
|
||||
// Cpu update
|
||||
dev_ctx.template HostAlloc<MT>(beta1_pow_out)[0] =
|
||||
beta1_ * beta1_pow.data<MT>()[0];
|
||||
dev_ctx.template HostAlloc<MT>(beta2_pow_out)[0] =
|
||||
beta2_ * beta2_pow.data<MT>()[0];
|
||||
}
|
||||
} else {
|
||||
if (grad_type == DataType::FLOAT32) {
|
||||
AdamKernelMEM<T, float, MT><<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
beta1_,
|
||||
beta2_,
|
||||
epsilon_,
|
||||
beta1_pow.data<MT>(),
|
||||
beta2_pow.data<MT>(),
|
||||
moment1.data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(moment1_out),
|
||||
moment2.data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(moment2_out),
|
||||
moment2_max_in_data,
|
||||
moment2_max_out_data,
|
||||
learning_rate.data<double>(),
|
||||
grad.data<float>(),
|
||||
param.data<T>(),
|
||||
dev_ctx.template Alloc<T>(param_out),
|
||||
master_in_data,
|
||||
master_out_data,
|
||||
param.numel(),
|
||||
amsgrad);
|
||||
} else {
|
||||
AdamKernelMEM<T, T, MT><<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
beta1_,
|
||||
beta2_,
|
||||
epsilon_,
|
||||
beta1_pow.data<MT>(),
|
||||
beta2_pow.data<MT>(),
|
||||
moment1.data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(moment1_out),
|
||||
moment2.data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(moment2_out),
|
||||
moment2_max_in_data,
|
||||
moment2_max_out_data,
|
||||
learning_rate.data<double>(),
|
||||
grad.data<T>(),
|
||||
param.data<T>(),
|
||||
dev_ctx.template Alloc<T>(param_out),
|
||||
master_in_data,
|
||||
master_out_data,
|
||||
param.numel(),
|
||||
amsgrad);
|
||||
}
|
||||
if (!use_global_beta_pow) {
|
||||
// Update with gpu
|
||||
UpdateBetaPow<MT><<<1, 1, 0, dev_ctx.stream()>>>(
|
||||
beta1_,
|
||||
beta2_,
|
||||
beta1_pow.data<MT>(),
|
||||
beta2_pow.data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(beta1_pow_out),
|
||||
dev_ctx.template Alloc<MT>(beta2_pow_out));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void MergedAdamKernel(
|
||||
const Context& dev_ctx,
|
||||
const std::vector<const DenseTensor*>& param,
|
||||
const std::vector<const DenseTensor*>& grad,
|
||||
const std::vector<const DenseTensor*>& learning_rate,
|
||||
const std::vector<const DenseTensor*>& moment1,
|
||||
const std::vector<const DenseTensor*>& moment2,
|
||||
const optional<std::vector<const DenseTensor*>>& moment2_max,
|
||||
const std::vector<const DenseTensor*>& beta1_pow,
|
||||
const std::vector<const DenseTensor*>& beta2_pow,
|
||||
const optional<std::vector<const DenseTensor*>>& master_param,
|
||||
const Scalar& beta1,
|
||||
const Scalar& beta2,
|
||||
const Scalar& epsilon,
|
||||
bool multi_precision,
|
||||
bool use_global_beta_pow,
|
||||
bool amsgrad,
|
||||
std::vector<DenseTensor*> param_out,
|
||||
std::vector<DenseTensor*> moment1_out,
|
||||
std::vector<DenseTensor*> moment2_out,
|
||||
std::vector<DenseTensor*> moment2_max_out,
|
||||
std::vector<DenseTensor*> beta1_pow_out,
|
||||
std::vector<DenseTensor*> beta2_pow_out,
|
||||
std::vector<DenseTensor*> master_param_out) {
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
VLOG(4) << "use_global_beta_pow:" << use_global_beta_pow;
|
||||
MT beta1_ = beta1.to<MT>();
|
||||
MT beta2_ = beta2.to<MT>();
|
||||
MT epsilon_ = epsilon.to<MT>();
|
||||
|
||||
size_t param_num = param.size();
|
||||
|
||||
for (size_t idx = 0; idx < param_num; idx++) {
|
||||
const MT* master_in_data =
|
||||
multi_precision ? master_param.get()[idx]->data<MT>() : nullptr;
|
||||
MT* master_out_data =
|
||||
multi_precision ? dev_ctx.template Alloc<MT>(master_param_out[idx])
|
||||
: nullptr;
|
||||
|
||||
const MT* moment2_max_in_data =
|
||||
amsgrad ? moment2_max.get()[idx]->data<MT>() : nullptr;
|
||||
MT* moment2_max_out_data =
|
||||
amsgrad ? dev_ctx.template Alloc<MT>(moment2_max_out[idx]) : nullptr;
|
||||
|
||||
// update param and moment
|
||||
int threads = 512;
|
||||
int64_t blocks_max = dev_ctx.GetCUDAMaxGridDimSize()[0];
|
||||
int blocks =
|
||||
std::min((param[idx]->numel() + threads - 1) / threads, blocks_max);
|
||||
|
||||
const auto grad_type = grad[idx]->dtype();
|
||||
if (beta1_pow[idx]->place() == CPUPlace() &&
|
||||
beta2_pow[idx]->place() == CPUPlace()) {
|
||||
// Compute with betapow in REG
|
||||
if (grad_type == DataType::FLOAT32) {
|
||||
AdamKernelREG<T, float, MT><<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
beta1_,
|
||||
beta2_,
|
||||
epsilon_,
|
||||
*beta1_pow[idx]->data<MT>(),
|
||||
*beta2_pow[idx]->data<MT>(),
|
||||
moment1[idx]->data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(moment1_out[idx]),
|
||||
moment2[idx]->data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(moment2_out[idx]),
|
||||
moment2_max_in_data,
|
||||
moment2_max_out_data,
|
||||
learning_rate[idx]->data<double>(),
|
||||
grad[idx]->data<float>(),
|
||||
param[idx]->data<T>(),
|
||||
dev_ctx.template Alloc<T>(param_out[idx]),
|
||||
master_in_data,
|
||||
master_out_data,
|
||||
param[idx]->numel(),
|
||||
amsgrad);
|
||||
} else {
|
||||
AdamKernelREG<T, T, MT><<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
beta1_,
|
||||
beta2_,
|
||||
epsilon_,
|
||||
*beta1_pow[idx]->data<MT>(),
|
||||
*beta2_pow[idx]->data<MT>(),
|
||||
moment1[idx]->data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(moment1_out[idx]),
|
||||
moment2[idx]->data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(moment2_out[idx]),
|
||||
moment2_max_in_data,
|
||||
moment2_max_out_data,
|
||||
learning_rate[idx]->data<double>(),
|
||||
grad[idx]->data<T>(),
|
||||
param[idx]->data<T>(),
|
||||
dev_ctx.template Alloc<T>(param_out[idx]),
|
||||
master_in_data,
|
||||
master_out_data,
|
||||
param[idx]->numel(),
|
||||
amsgrad);
|
||||
}
|
||||
if (!use_global_beta_pow) {
|
||||
// Cpu update
|
||||
dev_ctx.template HostAlloc<MT>(beta1_pow_out[idx])[0] =
|
||||
beta1_ * beta1_pow[idx]->data<MT>()[0];
|
||||
dev_ctx.template HostAlloc<MT>(beta2_pow_out[idx])[0] =
|
||||
beta2_ * beta2_pow[idx]->data<MT>()[0];
|
||||
}
|
||||
} else {
|
||||
if (grad_type == DataType::FLOAT32) {
|
||||
AdamKernelMEM<T, float, MT><<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
beta1_,
|
||||
beta2_,
|
||||
epsilon_,
|
||||
beta1_pow[idx]->data<MT>(),
|
||||
beta2_pow[idx]->data<MT>(),
|
||||
moment1[idx]->data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(moment1_out[idx]),
|
||||
moment2[idx]->data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(moment2_out[idx]),
|
||||
moment2_max_in_data,
|
||||
moment2_max_out_data,
|
||||
learning_rate[idx]->data<double>(),
|
||||
grad[idx]->data<float>(),
|
||||
param[idx]->data<T>(),
|
||||
dev_ctx.template Alloc<T>(param_out[idx]),
|
||||
master_in_data,
|
||||
master_out_data,
|
||||
param[idx]->numel(),
|
||||
amsgrad);
|
||||
} else {
|
||||
AdamKernelMEM<T, T, MT><<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
beta1_,
|
||||
beta2_,
|
||||
epsilon_,
|
||||
beta1_pow[idx]->data<MT>(),
|
||||
beta2_pow[idx]->data<MT>(),
|
||||
moment1[idx]->data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(moment1_out[idx]),
|
||||
moment2[idx]->data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(moment2_out[idx]),
|
||||
moment2_max_in_data,
|
||||
moment2_max_out_data,
|
||||
learning_rate[idx]->data<double>(),
|
||||
grad[idx]->data<T>(),
|
||||
param[idx]->data<T>(),
|
||||
dev_ctx.template Alloc<T>(param_out[idx]),
|
||||
master_in_data,
|
||||
master_out_data,
|
||||
param[idx]->numel(),
|
||||
amsgrad);
|
||||
}
|
||||
if (!use_global_beta_pow) {
|
||||
// Update with gpu
|
||||
UpdateBetaPow<MT><<<1, 1, 0, dev_ctx.stream()>>>(
|
||||
beta1_,
|
||||
beta2_,
|
||||
beta1_pow[idx]->data<MT>(),
|
||||
beta2_pow[idx]->data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(beta1_pow_out[idx]),
|
||||
dev_ctx.template Alloc<MT>(beta2_pow_out[idx]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(adam,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AdamDenseKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {
|
||||
kernel->InputAt(2).SetDataType(phi::DataType::FLOAT64);
|
||||
// Skip beta1_pow, beta2_pow, skip_update data transform
|
||||
kernel->InputAt(6).SetBackend(phi::Backend::ALL_BACKEND);
|
||||
kernel->InputAt(7).SetBackend(phi::Backend::ALL_BACKEND);
|
||||
kernel->InputAt(9).SetBackend(phi::Backend::ALL_BACKEND);
|
||||
|
||||
if (kernel_key.dtype() == phi::DataType::FLOAT16 ||
|
||||
kernel_key.dtype() == phi::DataType::BFLOAT16) {
|
||||
kernel->OutputAt(1).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(2).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(3).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(4).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(5).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(6).SetDataType(phi::DataType::FLOAT32);
|
||||
}
|
||||
kernel->OutputAt(4).SetBackend(phi::Backend::UNDEFINED);
|
||||
kernel->OutputAt(5).SetBackend(phi::Backend::UNDEFINED);
|
||||
}
|
||||
|
||||
PD_REGISTER_KERNEL(merged_adam,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::MergedAdamKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {
|
||||
kernel->InputAt(2).SetDataType(phi::DataType::FLOAT64);
|
||||
// Skip beta1_pow, beta2_pow data transform
|
||||
kernel->InputAt(6).SetBackend(phi::Backend::ALL_BACKEND);
|
||||
kernel->InputAt(7).SetBackend(phi::Backend::ALL_BACKEND);
|
||||
|
||||
if (kernel_key.dtype() == phi::DataType::FLOAT16 ||
|
||||
kernel_key.dtype() == phi::DataType::BFLOAT16) {
|
||||
kernel->OutputAt(1).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(2).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(3).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(4).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(5).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(6).SetDataType(phi::DataType::FLOAT32);
|
||||
}
|
||||
kernel->OutputAt(4).SetBackend(phi::Backend::UNDEFINED);
|
||||
kernel->OutputAt(5).SetBackend(phi::Backend::UNDEFINED);
|
||||
}
|
||||
@@ -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 "paddle/phi/kernels/adamax_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_launch_config.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
namespace phi {
|
||||
template <typename T, typename MT>
|
||||
__global__ void AdamaxGPUKernel(const T* param,
|
||||
const T* grad,
|
||||
const MT* learning_rate,
|
||||
const MT* moment,
|
||||
const MT* inf_norm,
|
||||
const MT* beta1_pow,
|
||||
const MT* master_param,
|
||||
MT d_beta1,
|
||||
MT d_beta2,
|
||||
MT d_epsilon,
|
||||
int64_t num,
|
||||
T* param_out,
|
||||
MT* moment_out,
|
||||
MT* inf_norm_out,
|
||||
MT* master_param_out) {
|
||||
int64_t idx =
|
||||
static_cast<int64_t>(blockIdx.x) * static_cast<int64_t>(blockDim.x) +
|
||||
static_cast<int64_t>(threadIdx.x);
|
||||
|
||||
MT lr = static_cast<MT>(learning_rate[0]);
|
||||
MT d_pow = static_cast<MT>(beta1_pow[0]);
|
||||
MT one = static_cast<MT>(1.0f);
|
||||
auto l_r = lr / (one - d_pow);
|
||||
|
||||
for (int64_t index = idx; index < num; index += gridDim.x * blockDim.x) {
|
||||
// load and cast input to MT
|
||||
MT d_param =
|
||||
master_param ? master_param[index] : static_cast<MT>(param[index]);
|
||||
MT d_grad = static_cast<MT>(grad[index]);
|
||||
MT d_moment = static_cast<MT>(moment[index]);
|
||||
MT d_inf = static_cast<MT>(inf_norm[index]);
|
||||
// compute
|
||||
auto mom_out = d_beta1 * d_moment + (one - d_beta1) * d_grad;
|
||||
auto norm_out = std::max(std::abs(d_grad), d_beta2 * d_inf + d_epsilon);
|
||||
auto out_data = d_param - l_r * (mom_out / norm_out);
|
||||
// store
|
||||
param_out[index] = static_cast<T>(out_data);
|
||||
moment_out[index] = static_cast<T>(mom_out);
|
||||
inf_norm_out[index] = static_cast<T>(norm_out);
|
||||
|
||||
if (master_param_out) {
|
||||
master_param_out[index] = out_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AdamaxKernel(const Context& dev_ctx,
|
||||
const DenseTensor& param,
|
||||
const DenseTensor& grad,
|
||||
const DenseTensor& learning_rate,
|
||||
const DenseTensor& moment,
|
||||
const DenseTensor& inf_norm,
|
||||
const DenseTensor& beta1_pow,
|
||||
const optional<DenseTensor>& master_param,
|
||||
float beta1,
|
||||
float beta2,
|
||||
float epsilon,
|
||||
bool multi_precision,
|
||||
DenseTensor* param_out,
|
||||
DenseTensor* moment_out,
|
||||
DenseTensor* inf_norm_out,
|
||||
DenseTensor* master_param_outs) {
|
||||
using MT = typename dtype::template MPTypeTrait<T>::Type;
|
||||
T* param_out_data = dev_ctx.template Alloc<T>(param_out);
|
||||
MT* moment_out_data = dev_ctx.template Alloc<MT>(moment_out);
|
||||
MT* inf_norm_out_data = dev_ctx.template Alloc<MT>(inf_norm_out);
|
||||
const MT* master_in_data =
|
||||
multi_precision ? master_param->data<MT>() : nullptr;
|
||||
MT* master_out_data =
|
||||
multi_precision ? dev_ctx.template Alloc<MT>(master_param_outs) : nullptr;
|
||||
PADDLE_ENFORCE_EQ(
|
||||
beta1_pow.numel(),
|
||||
1,
|
||||
errors::InvalidArgument("beta1 pow's size should be 1, but received "
|
||||
"value is:%d.",
|
||||
beta1_pow.numel()));
|
||||
|
||||
MT beta1_ = static_cast<MT>(beta1);
|
||||
MT beta2_ = static_cast<MT>(beta2);
|
||||
MT epsilon_ = static_cast<MT>(epsilon);
|
||||
|
||||
int64_t numel = param.numel();
|
||||
auto config = backends::gpu::GetGpuLaunchConfig1D(dev_ctx, numel, 1);
|
||||
int grid = config.block_per_grid.x;
|
||||
int block = config.thread_per_block.x;
|
||||
auto stream = dev_ctx.stream();
|
||||
|
||||
AdamaxGPUKernel<T, MT><<<block, grid, 0, stream>>>(param.data<T>(),
|
||||
grad.data<T>(),
|
||||
learning_rate.data<MT>(),
|
||||
moment.data<MT>(),
|
||||
inf_norm.data<MT>(),
|
||||
beta1_pow.data<MT>(),
|
||||
master_in_data,
|
||||
beta1_,
|
||||
beta2_,
|
||||
epsilon_,
|
||||
numel,
|
||||
param_out_data,
|
||||
moment_out_data,
|
||||
inf_norm_out_data,
|
||||
master_out_data);
|
||||
}
|
||||
} // namespace phi
|
||||
PD_REGISTER_KERNEL(
|
||||
adamax, GPU, ALL_LAYOUT, phi::AdamaxKernel, float, double, phi::float16) {
|
||||
if (kernel_key.dtype() == phi::DataType::FLOAT16) {
|
||||
kernel->OutputAt(1).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(2).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(3).SetDataType(phi::DataType::FLOAT32);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,911 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/adamw_kernel.h"
|
||||
|
||||
#include <math.h> // for sqrt in CPU and CUDA
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "glog/logging.h"
|
||||
#include "paddle/common/flags.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/common/memory_utils.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/core/tensor_utils.h"
|
||||
#include "paddle/phi/kernels/funcs/adam_functors.h"
|
||||
#include "paddle/phi/kernels/funcs/for_range.h"
|
||||
#include "paddle/phi/kernels/funcs/selected_rows_functor.h"
|
||||
|
||||
COMMON_DECLARE_bool(use_accuracy_compatible_kernel);
|
||||
|
||||
namespace phi {
|
||||
|
||||
// Template accessor design
|
||||
template <typename MT, bool IsCpu>
|
||||
struct BetaPowAccessor;
|
||||
|
||||
template <typename MT>
|
||||
struct BetaPowAccessor<MT, true> { // CPU accessor
|
||||
const MT beta1;
|
||||
const MT beta2;
|
||||
|
||||
BetaPowAccessor(const MT* beta1_pow, const MT* beta2_pow)
|
||||
: beta1(*beta1_pow), beta2(*beta2_pow) {}
|
||||
|
||||
__device__ MT GetBeta1() const { return beta1; }
|
||||
__device__ MT GetBeta2() const { return beta2; }
|
||||
};
|
||||
|
||||
template <typename MT>
|
||||
struct BetaPowAccessor<MT, false> { // GPU pointer
|
||||
const MT* beta1_pow;
|
||||
const MT* beta2_pow;
|
||||
|
||||
BetaPowAccessor(const MT* beta1, const MT* beta2)
|
||||
: beta1_pow(beta1), beta2_pow(beta2) {}
|
||||
|
||||
__device__ MT GetBeta1() const { return *beta1_pow; }
|
||||
__device__ MT GetBeta2() const { return *beta2_pow; }
|
||||
};
|
||||
|
||||
// Unified kernel template
|
||||
template <typename T, // Parameter type
|
||||
typename TG, // Gradient type
|
||||
typename MT, // Multi-precision type
|
||||
typename TM, // Moment estimation type
|
||||
typename BetaAccessor>
|
||||
__global__ void AdamWKernel(MT beta1,
|
||||
MT beta2,
|
||||
MT epsilon,
|
||||
MT coeff,
|
||||
MT lr_ratio,
|
||||
const double* lr_,
|
||||
const TG* grad,
|
||||
const T* param,
|
||||
T* param_out,
|
||||
const MT* master_param,
|
||||
MT* master_param_out,
|
||||
const TM* moment1,
|
||||
TM* moment1_out,
|
||||
const TM* moment2,
|
||||
TM* moment2_out,
|
||||
const TM* moment2_max,
|
||||
TM* moment2_max_out,
|
||||
BetaAccessor beta_accessor,
|
||||
int64_t ndim,
|
||||
bool amsgrad) {
|
||||
int64_t id =
|
||||
static_cast<int64_t>(blockIdx.x) * static_cast<int64_t>(blockDim.x) +
|
||||
static_cast<int64_t>(threadIdx.x);
|
||||
MT lr = *lr_ * lr_ratio;
|
||||
// Get beta powers
|
||||
MT beta1_pow = beta_accessor.GetBeta1();
|
||||
MT beta2_pow = beta_accessor.GetBeta2();
|
||||
|
||||
for (; id < ndim; id += gridDim.x * blockDim.x) {
|
||||
MT p = master_param ? master_param[id] : static_cast<MT>(param[id]);
|
||||
MT g = static_cast<MT>(grad[id]);
|
||||
MT mom1 = static_cast<MT>(moment1[id]);
|
||||
MT mom2 = static_cast<MT>(moment2[id]);
|
||||
|
||||
p *= (static_cast<MT>(1.0) - lr * coeff);
|
||||
|
||||
mom1 = beta1 * mom1 + (static_cast<MT>(1.0) - beta1) * g;
|
||||
mom2 = beta2 * mom2 + (static_cast<MT>(1.0) - beta2) * g * g;
|
||||
|
||||
MT denom;
|
||||
if (amsgrad) {
|
||||
MT mom2_max = static_cast<MT>(moment2_max[id]);
|
||||
MT mom2_max_ = std::max(mom2, mom2_max);
|
||||
moment2_max_out[id] = mom2_max_;
|
||||
|
||||
denom =
|
||||
(sqrt(mom2_max_) / sqrt(static_cast<MT>(1.0) - beta2_pow)) + epsilon;
|
||||
} else {
|
||||
denom = (sqrt(mom2) / sqrt(static_cast<MT>(1.0) - beta2_pow)) + epsilon;
|
||||
}
|
||||
|
||||
p += (mom1 / denom) * (-(lr / (static_cast<MT>(1.0) - beta1_pow)));
|
||||
|
||||
moment1_out[id] = mom1;
|
||||
moment2_out[id] = mom2;
|
||||
param_out[id] = static_cast<T>(p);
|
||||
if (master_param_out) {
|
||||
master_param_out[id] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Beta power update kernel
|
||||
template <typename MT>
|
||||
__global__ void UpdateBetaPowKernel(MT beta1,
|
||||
MT beta2,
|
||||
const MT* beta1_pow,
|
||||
const MT* beta2_pow,
|
||||
MT* beta1_pow_out,
|
||||
MT* beta2_pow_out) {
|
||||
beta1_pow_out[0] = beta1 * beta1_pow[0];
|
||||
beta2_pow_out[0] = beta2 * beta2_pow[0];
|
||||
}
|
||||
|
||||
// Forward declaration
|
||||
template <typename T, typename Context>
|
||||
PADDLE_API void AdamwDenseKernel_compatible(
|
||||
const Context& dev_ctx,
|
||||
const DenseTensor& param,
|
||||
const DenseTensor& grad,
|
||||
const DenseTensor& learning_rate,
|
||||
const DenseTensor& moment1,
|
||||
const DenseTensor& moment2,
|
||||
const optional<DenseTensor>& moment2_max,
|
||||
const DenseTensor& beta1_pow,
|
||||
const DenseTensor& beta2_pow,
|
||||
const optional<DenseTensor>& master_param,
|
||||
const optional<DenseTensor>& skip_update,
|
||||
const Scalar& beta1,
|
||||
const Scalar& beta2,
|
||||
const Scalar& epsilon,
|
||||
double lr_ratio,
|
||||
double coeff,
|
||||
bool with_decay,
|
||||
bool lazy_mode,
|
||||
int64_t min_row_size_to_use_multithread,
|
||||
bool multi_precision,
|
||||
bool use_global_beta_pow,
|
||||
bool amsgrad,
|
||||
DenseTensor* param_out,
|
||||
DenseTensor* moment1_out,
|
||||
DenseTensor* moment2_out,
|
||||
DenseTensor* moment2_max_out,
|
||||
DenseTensor* beta1_pow_out,
|
||||
DenseTensor* beta2_pow_out,
|
||||
DenseTensor* master_param_outs);
|
||||
|
||||
template <typename T, typename Context>
|
||||
PADDLE_API void AdamwDenseKernel(const Context& dev_ctx,
|
||||
const DenseTensor& param,
|
||||
const DenseTensor& grad,
|
||||
const DenseTensor& learning_rate,
|
||||
const DenseTensor& moment1,
|
||||
const DenseTensor& moment2,
|
||||
const optional<DenseTensor>& moment2_max,
|
||||
const DenseTensor& beta1_pow,
|
||||
const DenseTensor& beta2_pow,
|
||||
const optional<DenseTensor>& master_param,
|
||||
const optional<DenseTensor>& skip_update,
|
||||
const Scalar& beta1,
|
||||
const Scalar& beta2,
|
||||
const Scalar& epsilon,
|
||||
double lr_ratio,
|
||||
double coeff,
|
||||
bool with_decay,
|
||||
bool lazy_mode,
|
||||
int64_t min_row_size_to_use_multithread,
|
||||
bool multi_precision,
|
||||
bool use_global_beta_pow,
|
||||
bool amsgrad,
|
||||
DenseTensor* param_out,
|
||||
DenseTensor* moment1_out,
|
||||
DenseTensor* moment2_out,
|
||||
DenseTensor* moment2_max_out,
|
||||
DenseTensor* beta1_pow_out,
|
||||
DenseTensor* beta2_pow_out,
|
||||
DenseTensor* master_param_outs) {
|
||||
if (FLAGS_use_accuracy_compatible_kernel) {
|
||||
AdamwDenseKernel_compatible<T, Context>(dev_ctx,
|
||||
param,
|
||||
grad,
|
||||
learning_rate,
|
||||
moment1,
|
||||
moment2,
|
||||
moment2_max,
|
||||
beta1_pow,
|
||||
beta2_pow,
|
||||
master_param,
|
||||
skip_update,
|
||||
beta1,
|
||||
beta2,
|
||||
epsilon,
|
||||
lr_ratio,
|
||||
coeff,
|
||||
with_decay,
|
||||
lazy_mode,
|
||||
min_row_size_to_use_multithread,
|
||||
multi_precision,
|
||||
use_global_beta_pow,
|
||||
amsgrad,
|
||||
param_out,
|
||||
moment1_out,
|
||||
moment2_out,
|
||||
moment2_max_out,
|
||||
beta1_pow_out,
|
||||
beta2_pow_out,
|
||||
master_param_outs);
|
||||
return;
|
||||
}
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
MT coeff_ = static_cast<MT>(coeff);
|
||||
MT lr_ratio_ = static_cast<MT>(lr_ratio);
|
||||
|
||||
bool skip_update_ = false;
|
||||
if (skip_update.is_initialized()) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
skip_update->numel(),
|
||||
1,
|
||||
errors::InvalidArgument("Input(SkipUpdate) size must be 1, but get %d",
|
||||
skip_update->numel()));
|
||||
std::vector<bool> skip_update_vec;
|
||||
TensorToVector(*skip_update, dev_ctx, &skip_update_vec);
|
||||
skip_update_ = skip_update_vec[0];
|
||||
}
|
||||
|
||||
// skip_update=true, just copy input to output, and TensorCopy will call
|
||||
// mutable_data
|
||||
if (skip_update_) {
|
||||
VLOG(4) << "Adamw skip update";
|
||||
Copy(dev_ctx, param, dev_ctx.GetPlace(), false, param_out);
|
||||
Copy(dev_ctx, moment1, dev_ctx.GetPlace(), false, moment1_out);
|
||||
Copy(dev_ctx, moment2, dev_ctx.GetPlace(), false, moment2_out);
|
||||
if (amsgrad) {
|
||||
Copy(dev_ctx,
|
||||
moment2_max.get(),
|
||||
dev_ctx.GetPlace(),
|
||||
false,
|
||||
moment2_max_out);
|
||||
}
|
||||
if (!use_global_beta_pow) {
|
||||
Copy(dev_ctx, beta1_pow, beta1_pow.place(), false, beta1_pow_out);
|
||||
Copy(dev_ctx, beta2_pow, beta2_pow.place(), false, beta2_pow_out);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// if with_decay = false, coeff = 0
|
||||
if (!with_decay) {
|
||||
coeff_ = static_cast<MT>(0.0);
|
||||
}
|
||||
|
||||
MT beta1_ = beta1.to<MT>();
|
||||
MT beta2_ = beta2.to<MT>();
|
||||
MT epsilon_ = epsilon.to<MT>();
|
||||
VLOG(3) << "beta1_pow.numel() : " << beta1_pow.numel()
|
||||
<< "beta2_pow.numel() : " << beta2_pow.numel();
|
||||
VLOG(3) << "param.numel(): " << param.numel();
|
||||
PADDLE_ENFORCE_EQ(
|
||||
beta1_pow_out->numel(),
|
||||
1,
|
||||
errors::InvalidArgument("beta1 pow output size should be 1, but received "
|
||||
"value is:%d.",
|
||||
beta1_pow_out->numel()));
|
||||
|
||||
PADDLE_ENFORCE_EQ(
|
||||
beta2_pow_out->numel(),
|
||||
1,
|
||||
errors::InvalidArgument("beta2 pow output size should be 1, but received "
|
||||
"value is:%d.",
|
||||
beta2_pow_out->numel()));
|
||||
|
||||
const MT* master_in_data =
|
||||
multi_precision ? master_param->data<MT>() : nullptr;
|
||||
MT* master_out_data =
|
||||
multi_precision ? dev_ctx.template Alloc<MT>(master_param_outs) : nullptr;
|
||||
|
||||
const MT* moment2_max_in_data =
|
||||
amsgrad ? moment2_max.get().data<MT>() : nullptr;
|
||||
MT* moment2_max_out_data =
|
||||
amsgrad ? dev_ctx.template Alloc<MT>(moment2_max_out) : nullptr;
|
||||
|
||||
// update param and moment
|
||||
int threads = 512;
|
||||
int64_t blocks_max = dev_ctx.GetCUDAMaxGridDimSize()[0];
|
||||
int blocks = std::min((param.numel() + threads - 1) / threads, blocks_max);
|
||||
|
||||
// Determine BetaPow location
|
||||
const bool beta_pow_on_cpu =
|
||||
beta1_pow.place() == CPUPlace() && beta2_pow.place() == CPUPlace();
|
||||
|
||||
// Determine gradient type
|
||||
const bool use_bfloat32_grad = grad.dtype() == DataType::FLOAT32;
|
||||
// Determine moment type
|
||||
const bool use_bfloat16_moments = moment1.dtype() == DataType::BFLOAT16 &&
|
||||
moment2.dtype() == DataType::BFLOAT16;
|
||||
|
||||
#define LAUNCH_ADAMW_KERNEL(MOMENT_T) \
|
||||
if (beta_pow_on_cpu) { \
|
||||
BetaPowAccessor<MT, true> accessor(beta1_pow.data<MT>(), \
|
||||
beta2_pow.data<MT>()); \
|
||||
if (use_bfloat32_grad) { \
|
||||
AdamWKernel<T, float, MT, MOMENT_T, BetaPowAccessor<MT, true>> \
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>( \
|
||||
beta1_, \
|
||||
beta2_, \
|
||||
epsilon_, \
|
||||
coeff_, \
|
||||
lr_ratio_, \
|
||||
learning_rate.data<double>(), \
|
||||
grad.data<float>(), \
|
||||
param.data<T>(), \
|
||||
dev_ctx.template Alloc<T>(param_out), \
|
||||
master_in_data, \
|
||||
master_out_data, \
|
||||
moment1.data<MOMENT_T>(), \
|
||||
dev_ctx.template Alloc<MOMENT_T>(moment1_out), \
|
||||
moment2.data<MOMENT_T>(), \
|
||||
dev_ctx.template Alloc<MOMENT_T>(moment2_out), \
|
||||
moment2_max ? moment2_max->data<MOMENT_T>() : nullptr, \
|
||||
amsgrad ? dev_ctx.template Alloc<MOMENT_T>(moment2_max_out) \
|
||||
: nullptr, \
|
||||
accessor, \
|
||||
param.numel(), \
|
||||
amsgrad); \
|
||||
} else { \
|
||||
AdamWKernel<T, T, MT, MOMENT_T, BetaPowAccessor<MT, true>> \
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>( \
|
||||
beta1_, \
|
||||
beta2_, \
|
||||
epsilon_, \
|
||||
coeff_, \
|
||||
lr_ratio_, \
|
||||
learning_rate.data<double>(), \
|
||||
grad.data<T>(), \
|
||||
param.data<T>(), \
|
||||
dev_ctx.template Alloc<T>(param_out), \
|
||||
master_in_data, \
|
||||
master_out_data, \
|
||||
moment1.data<MOMENT_T>(), \
|
||||
dev_ctx.template Alloc<MOMENT_T>(moment1_out), \
|
||||
moment2.data<MOMENT_T>(), \
|
||||
dev_ctx.template Alloc<MOMENT_T>(moment2_out), \
|
||||
moment2_max ? moment2_max->data<MOMENT_T>() : nullptr, \
|
||||
amsgrad ? dev_ctx.template Alloc<MOMENT_T>(moment2_max_out) \
|
||||
: nullptr, \
|
||||
accessor, \
|
||||
param.numel(), \
|
||||
amsgrad); \
|
||||
} \
|
||||
} else { \
|
||||
BetaPowAccessor<MT, false> accessor(beta1_pow.data<MT>(), \
|
||||
beta2_pow.data<MT>()); \
|
||||
if (use_bfloat32_grad) { \
|
||||
AdamWKernel<T, float, MT, MOMENT_T, BetaPowAccessor<MT, false>> \
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>( \
|
||||
beta1_, \
|
||||
beta2_, \
|
||||
epsilon_, \
|
||||
coeff_, \
|
||||
lr_ratio_, \
|
||||
learning_rate.data<double>(), \
|
||||
grad.data<float>(), \
|
||||
param.data<T>(), \
|
||||
dev_ctx.template Alloc<T>(param_out), \
|
||||
master_in_data, \
|
||||
master_out_data, \
|
||||
moment1.data<MOMENT_T>(), \
|
||||
dev_ctx.template Alloc<MOMENT_T>(moment1_out), \
|
||||
moment2.data<MOMENT_T>(), \
|
||||
dev_ctx.template Alloc<MOMENT_T>(moment2_out), \
|
||||
moment2_max ? moment2_max->data<MOMENT_T>() : nullptr, \
|
||||
amsgrad ? dev_ctx.template Alloc<MOMENT_T>(moment2_max_out) \
|
||||
: nullptr, \
|
||||
accessor, \
|
||||
param.numel(), \
|
||||
amsgrad); \
|
||||
} else { \
|
||||
AdamWKernel<T, T, MT, MOMENT_T, BetaPowAccessor<MT, false>> \
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>( \
|
||||
beta1_, \
|
||||
beta2_, \
|
||||
epsilon_, \
|
||||
coeff_, \
|
||||
lr_ratio_, \
|
||||
learning_rate.data<double>(), \
|
||||
grad.data<T>(), \
|
||||
param.data<T>(), \
|
||||
dev_ctx.template Alloc<T>(param_out), \
|
||||
master_in_data, \
|
||||
master_out_data, \
|
||||
moment1.data<MOMENT_T>(), \
|
||||
dev_ctx.template Alloc<MOMENT_T>(moment1_out), \
|
||||
moment2.data<MOMENT_T>(), \
|
||||
dev_ctx.template Alloc<MOMENT_T>(moment2_out), \
|
||||
moment2_max ? moment2_max->data<MOMENT_T>() : nullptr, \
|
||||
amsgrad ? dev_ctx.template Alloc<MOMENT_T>(moment2_max_out) \
|
||||
: nullptr, \
|
||||
accessor, \
|
||||
param.numel(), \
|
||||
amsgrad); \
|
||||
} \
|
||||
}
|
||||
|
||||
// Select template instantiation based on moment type
|
||||
if (use_bfloat16_moments) {
|
||||
LAUNCH_ADAMW_KERNEL(bfloat16)
|
||||
} else {
|
||||
LAUNCH_ADAMW_KERNEL(MT)
|
||||
}
|
||||
#undef LAUNCH_ADAMW_KERNEL
|
||||
|
||||
// Update beta_pow
|
||||
if (!use_global_beta_pow) {
|
||||
if (beta_pow_on_cpu) {
|
||||
auto* beta1_pow_out_data = dev_ctx.template HostAlloc<MT>(beta1_pow_out);
|
||||
auto* beta2_pow_out_data = dev_ctx.template HostAlloc<MT>(beta2_pow_out);
|
||||
beta1_pow_out_data[0] = beta1_ * beta1_pow.data<MT>()[0];
|
||||
beta2_pow_out_data[0] = beta2_ * beta2_pow.data<MT>()[0];
|
||||
} else {
|
||||
UpdateBetaPowKernel<MT><<<1, 1, 0, dev_ctx.stream()>>>(
|
||||
beta1_,
|
||||
beta2_,
|
||||
beta1_pow.data<MT>(),
|
||||
beta2_pow.data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(beta1_pow_out),
|
||||
dev_ctx.template Alloc<MT>(beta2_pow_out));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
template <bool IsCpu>
|
||||
struct AdamWLrAccessor;
|
||||
|
||||
// cpu
|
||||
template <>
|
||||
struct AdamWLrAccessor<true> {
|
||||
const double lr_double;
|
||||
|
||||
explicit AdamWLrAccessor(double lr) : lr_double(lr) {}
|
||||
|
||||
__device__ __forceinline__ double GetLrDouble() const { return lr_double; }
|
||||
};
|
||||
|
||||
// gpu
|
||||
template <>
|
||||
struct AdamWLrAccessor<false> {
|
||||
const double* lr;
|
||||
const double lr_ratio;
|
||||
|
||||
AdamWLrAccessor(const double* lr, double lr_ratio)
|
||||
: lr(lr), lr_ratio(lr_ratio) {}
|
||||
|
||||
__device__ __forceinline__ double GetLrDouble() const {
|
||||
return *lr * lr_ratio;
|
||||
}
|
||||
};
|
||||
|
||||
// Device-side pow matching torch's at::native::pow_ (promotes float exp to
|
||||
// double, then calls ::pow(double, double))
|
||||
template <typename Base_type, typename Exp_type>
|
||||
static __device__ __forceinline__ Base_type torch_pow_(Base_type base,
|
||||
Exp_type exp) {
|
||||
return ::pow(base, exp);
|
||||
}
|
||||
|
||||
// Accuracy-compatible bias correction: computes 1-beta^step_count on device,
|
||||
// matching torch's FusedAdamMathFunctor. After torch's "Use opmath_t and not
|
||||
// double compute" change, the bias correction is computed in opmath_t (float
|
||||
// for fp32/fp16/bf16, double for fp64), with beta and step_count both cast to
|
||||
// opmath_t before pow_. We therefore compute everything in MT (= opmath_t).
|
||||
template <typename MT, bool IsCpu>
|
||||
struct AdamWBiasCorrAccessorCompat;
|
||||
|
||||
// CPU specialization: step_count pre-computed on host
|
||||
template <typename MT>
|
||||
struct AdamWBiasCorrAccessorCompat<MT, true> {
|
||||
const double beta1;
|
||||
const double beta2;
|
||||
const float step_count;
|
||||
|
||||
AdamWBiasCorrAccessorCompat(double b1, double b2, float sc)
|
||||
: beta1(b1), beta2(b2), step_count(sc) {}
|
||||
|
||||
__device__ __forceinline__ MT GetBc1() const {
|
||||
return static_cast<MT>(1) -
|
||||
torch_pow_(static_cast<MT>(beta1), static_cast<MT>(step_count));
|
||||
}
|
||||
__device__ __forceinline__ MT GetBc2() const {
|
||||
return static_cast<MT>(1) -
|
||||
torch_pow_(static_cast<MT>(beta2), static_cast<MT>(step_count));
|
||||
}
|
||||
};
|
||||
|
||||
// GPU specialization: recover step_count from beta1_pow pointer on device
|
||||
template <typename MT>
|
||||
struct AdamWBiasCorrAccessorCompat<MT, false> {
|
||||
const double beta1;
|
||||
const double beta2;
|
||||
const MT* beta1_pow;
|
||||
|
||||
AdamWBiasCorrAccessorCompat(double b1, double b2, const MT* bp1)
|
||||
: beta1(b1), beta2(b2), beta1_pow(bp1) {}
|
||||
|
||||
__device__ __forceinline__ MT GetStepCount() const {
|
||||
return static_cast<MT>(
|
||||
::round(::log(static_cast<double>(*beta1_pow)) / ::log(beta1)));
|
||||
}
|
||||
|
||||
__device__ __forceinline__ MT GetBc1() const {
|
||||
return static_cast<MT>(1) -
|
||||
torch_pow_(static_cast<MT>(beta1), GetStepCount());
|
||||
}
|
||||
__device__ __forceinline__ MT GetBc2() const {
|
||||
return static_cast<MT>(1) -
|
||||
torch_pow_(static_cast<MT>(beta2), GetStepCount());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, // Parameter type (may be fp16/bf16)
|
||||
typename TG, // Gradient type
|
||||
typename MT, // Master precision type (= opmath_t, float for
|
||||
// float/fp16/bf16)
|
||||
typename TM, // Moment estimation type (can be bfloat16)
|
||||
typename LrAccessor,
|
||||
typename BiasCorrAccessor>
|
||||
__global__ void AdamWStyleKernel(const double beta1,
|
||||
const double beta2,
|
||||
const double epsilon,
|
||||
const double weight_decay,
|
||||
LrAccessor lr_accessor,
|
||||
BiasCorrAccessor bias_corr_accessor,
|
||||
const TG* __restrict__ grad,
|
||||
const T* __restrict__ param,
|
||||
T* __restrict__ param_out,
|
||||
const MT* __restrict__ master_param,
|
||||
MT* __restrict__ master_param_out,
|
||||
const TM* __restrict__ moment1,
|
||||
TM* __restrict__ moment1_out,
|
||||
const TM* __restrict__ moment2,
|
||||
TM* __restrict__ moment2_out,
|
||||
const TM* __restrict__ moment2_max,
|
||||
TM* __restrict__ moment2_max_out,
|
||||
int64_t ndim,
|
||||
bool amsgrad) {
|
||||
// Matches torch >= 2.12's fused Adam(W) math after PR#173224 (use fma) and
|
||||
// PR#173227 (use opmath_t, not double): every scalar lives in opmath_t
|
||||
// (== MT, float for fp32/fp16/bf16, double for fp64) and the moment updates
|
||||
// use nested fma in opmath_t.
|
||||
__shared__ MT lr_weight_decay_shared;
|
||||
__shared__ MT bias_correction2_sqrt_shared;
|
||||
__shared__ MT step_size_shared;
|
||||
|
||||
const MT beta1_o = static_cast<MT>(beta1);
|
||||
const MT beta2_o = static_cast<MT>(beta2);
|
||||
const MT eps_o = static_cast<MT>(epsilon);
|
||||
|
||||
if (threadIdx.x == 0) {
|
||||
// lr cast to opmath_t (matches lr_opmath = static_cast<opmath_t>(lr)).
|
||||
const MT lr_o = static_cast<MT>(lr_accessor.GetLrDouble());
|
||||
// bias_correction{1,2} are computed in opmath_t inside the accessor.
|
||||
const MT bias_correction1 = bias_corr_accessor.GetBc1();
|
||||
const MT bias_correction2 = bias_corr_accessor.GetBc2();
|
||||
bias_correction2_sqrt_shared = static_cast<MT>(sqrt(bias_correction2));
|
||||
// step_size = lr / bias_correction1 (opmath_t / opmath_t).
|
||||
step_size_shared = lr_o / bias_correction1;
|
||||
// weight decay: param -= lr * weight_decay * param (all opmath_t).
|
||||
lr_weight_decay_shared = lr_o * static_cast<MT>(weight_decay);
|
||||
}
|
||||
__syncthreads();
|
||||
|
||||
const MT lr_weight_decay = lr_weight_decay_shared;
|
||||
const MT bias_correction2_sqrt = bias_correction2_sqrt_shared;
|
||||
const MT step_size = step_size_shared;
|
||||
|
||||
int64_t id =
|
||||
static_cast<int64_t>(blockIdx.x) * static_cast<int64_t>(blockDim.x) +
|
||||
static_cast<int64_t>(threadIdx.x);
|
||||
|
||||
for (; id < ndim; id += static_cast<int64_t>(gridDim.x) *
|
||||
static_cast<int64_t>(blockDim.x)) {
|
||||
MT p = master_param ? master_param[id] : static_cast<MT>(param[id]);
|
||||
MT g = static_cast<MT>(grad[id]);
|
||||
MT exp_avg = static_cast<MT>(moment1[id]);
|
||||
MT exp_avg_sq = static_cast<MT>(moment2[id]);
|
||||
|
||||
// Weight decay: param -= lr * weight_decay * param
|
||||
if (weight_decay != 0) {
|
||||
p -= lr_weight_decay * p;
|
||||
}
|
||||
|
||||
// exp_avg = fma(beta1, exp_avg, fma(-beta1, grad, grad))
|
||||
exp_avg = fma(beta1_o, exp_avg, fma(-beta1_o, g, g));
|
||||
// exp_avg_sq = fma(beta2, exp_avg_sq, fma(-beta2, grad*grad, grad*grad))
|
||||
const MT g_sq = g * g;
|
||||
exp_avg_sq = fma(beta2_o, exp_avg_sq, fma(-beta2_o, g_sq, g_sq));
|
||||
|
||||
MT denom;
|
||||
if (amsgrad) {
|
||||
MT max_exp_avg_sq_val = static_cast<MT>(moment2_max[id]);
|
||||
max_exp_avg_sq_val =
|
||||
max_exp_avg_sq_val > exp_avg_sq ? max_exp_avg_sq_val : exp_avg_sq;
|
||||
moment2_max_out[id] = static_cast<TM>(max_exp_avg_sq_val);
|
||||
denom = (sqrt(max_exp_avg_sq_val) / bias_correction2_sqrt) + eps_o;
|
||||
} else {
|
||||
denom = (sqrt(exp_avg_sq) / bias_correction2_sqrt) + eps_o;
|
||||
}
|
||||
|
||||
// param -= step_size * exp_avg / denom
|
||||
p -= step_size * exp_avg / denom;
|
||||
|
||||
moment1_out[id] = static_cast<TM>(exp_avg);
|
||||
moment2_out[id] = static_cast<TM>(exp_avg_sq);
|
||||
param_out[id] = static_cast<T>(p);
|
||||
if (master_param_out) {
|
||||
master_param_out[id] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
PADDLE_API void AdamwDenseKernel_compatible(
|
||||
const Context& dev_ctx,
|
||||
const DenseTensor& param,
|
||||
const DenseTensor& grad,
|
||||
const DenseTensor& learning_rate,
|
||||
const DenseTensor& moment1,
|
||||
const DenseTensor& moment2,
|
||||
const optional<DenseTensor>& moment2_max,
|
||||
const DenseTensor& beta1_pow,
|
||||
const DenseTensor& beta2_pow,
|
||||
const optional<DenseTensor>& master_param,
|
||||
const optional<DenseTensor>& skip_update,
|
||||
const Scalar& beta1,
|
||||
const Scalar& beta2,
|
||||
const Scalar& epsilon,
|
||||
double lr_ratio,
|
||||
double coeff,
|
||||
bool with_decay,
|
||||
bool lazy_mode,
|
||||
int64_t min_row_size_to_use_multithread,
|
||||
bool multi_precision,
|
||||
bool use_global_beta_pow,
|
||||
bool amsgrad,
|
||||
DenseTensor* param_out,
|
||||
DenseTensor* moment1_out,
|
||||
DenseTensor* moment2_out,
|
||||
DenseTensor* moment2_max_out,
|
||||
DenseTensor* beta1_pow_out,
|
||||
DenseTensor* beta2_pow_out,
|
||||
DenseTensor* master_param_outs) {
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
|
||||
bool skip_update_ = false;
|
||||
if (skip_update.is_initialized()) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
skip_update->numel(),
|
||||
1,
|
||||
errors::InvalidArgument("Input(SkipUpdate) size must be 1, but get %d",
|
||||
skip_update->numel()));
|
||||
std::vector<bool> skip_update_vec;
|
||||
TensorToVector(*skip_update, dev_ctx, &skip_update_vec);
|
||||
skip_update_ = skip_update_vec[0];
|
||||
}
|
||||
|
||||
if (skip_update_) {
|
||||
VLOG(4) << "Adamw skip update";
|
||||
Copy(dev_ctx, param, dev_ctx.GetPlace(), false, param_out);
|
||||
Copy(dev_ctx, moment1, dev_ctx.GetPlace(), false, moment1_out);
|
||||
Copy(dev_ctx, moment2, dev_ctx.GetPlace(), false, moment2_out);
|
||||
if (amsgrad) {
|
||||
Copy(dev_ctx,
|
||||
moment2_max.get(),
|
||||
dev_ctx.GetPlace(),
|
||||
false,
|
||||
moment2_max_out);
|
||||
}
|
||||
if (!use_global_beta_pow) {
|
||||
Copy(dev_ctx, beta1_pow, beta1_pow.place(), false, beta1_pow_out);
|
||||
Copy(dev_ctx, beta2_pow, beta2_pow.place(), false, beta2_pow_out);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// weight_decay: if with_decay is false, set to 0 (matching torch behavior)
|
||||
double weight_decay = with_decay ? coeff : 0.0;
|
||||
|
||||
double beta1_ = beta1.to<double>();
|
||||
double beta2_ = beta2.to<double>();
|
||||
double epsilon_ = epsilon.to<double>();
|
||||
|
||||
PADDLE_ENFORCE_EQ(
|
||||
beta1_pow_out->numel(),
|
||||
1,
|
||||
errors::InvalidArgument("beta1 pow output size should be 1, but received "
|
||||
"value is:%d.",
|
||||
beta1_pow_out->numel()));
|
||||
PADDLE_ENFORCE_EQ(
|
||||
beta2_pow_out->numel(),
|
||||
1,
|
||||
errors::InvalidArgument("beta2 pow output size should be 1, but received "
|
||||
"value is:%d.",
|
||||
beta2_pow_out->numel()));
|
||||
|
||||
const bool beta_pow_on_cpu =
|
||||
beta1_pow.place() == CPUPlace() && beta2_pow.place() == CPUPlace();
|
||||
|
||||
// Get learning rate as double. For GPU learning_rate, load it in the CUDA
|
||||
// kernel to avoid a host copy and synchronization.
|
||||
const bool lr_on_cpu = learning_rate.place() == CPUPlace();
|
||||
double lr_double = 0.0;
|
||||
if (lr_on_cpu) {
|
||||
lr_double = learning_rate.data<double>()[0] * lr_ratio;
|
||||
}
|
||||
|
||||
const MT* master_in_data =
|
||||
multi_precision ? master_param->data<MT>() : nullptr;
|
||||
MT* master_out_data =
|
||||
multi_precision ? dev_ctx.template Alloc<MT>(master_param_outs) : nullptr;
|
||||
|
||||
// Launch kernel
|
||||
int threads = 512;
|
||||
int64_t blocks_max = dev_ctx.GetCUDAMaxGridDimSize()[0];
|
||||
int blocks = std::min((param.numel() + threads - 1) / threads, blocks_max);
|
||||
|
||||
// Determine gradient type
|
||||
const bool use_bfloat32_grad = grad.dtype() == DataType::FLOAT32;
|
||||
// Determine moment type
|
||||
const bool use_bfloat16_moments = moment1.dtype() == DataType::BFLOAT16 &&
|
||||
moment2.dtype() == DataType::BFLOAT16;
|
||||
|
||||
#define LAUNCH_ADAMW_STYLE_KERNEL(MOMENT_T) \
|
||||
if (use_bfloat32_grad) { \
|
||||
AdamWStyleKernel<T, \
|
||||
float, \
|
||||
MT, \
|
||||
MOMENT_T, \
|
||||
decltype(lr_accessor), \
|
||||
decltype(bias_corr_accessor)> \
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>( \
|
||||
beta1_, \
|
||||
beta2_, \
|
||||
epsilon_, \
|
||||
weight_decay, \
|
||||
lr_accessor, \
|
||||
bias_corr_accessor, \
|
||||
grad.data<float>(), \
|
||||
param.data<T>(), \
|
||||
dev_ctx.template Alloc<T>(param_out), \
|
||||
master_in_data, \
|
||||
master_out_data, \
|
||||
moment1.data<MOMENT_T>(), \
|
||||
dev_ctx.template Alloc<MOMENT_T>(moment1_out), \
|
||||
moment2.data<MOMENT_T>(), \
|
||||
dev_ctx.template Alloc<MOMENT_T>(moment2_out), \
|
||||
amsgrad ? moment2_max->data<MOMENT_T>() : nullptr, \
|
||||
amsgrad ? dev_ctx.template Alloc<MOMENT_T>(moment2_max_out) \
|
||||
: nullptr, \
|
||||
param.numel(), \
|
||||
amsgrad); \
|
||||
} else { \
|
||||
AdamWStyleKernel<T, \
|
||||
T, \
|
||||
MT, \
|
||||
MOMENT_T, \
|
||||
decltype(lr_accessor), \
|
||||
decltype(bias_corr_accessor)> \
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>( \
|
||||
beta1_, \
|
||||
beta2_, \
|
||||
epsilon_, \
|
||||
weight_decay, \
|
||||
lr_accessor, \
|
||||
bias_corr_accessor, \
|
||||
grad.data<T>(), \
|
||||
param.data<T>(), \
|
||||
dev_ctx.template Alloc<T>(param_out), \
|
||||
master_in_data, \
|
||||
master_out_data, \
|
||||
moment1.data<MOMENT_T>(), \
|
||||
dev_ctx.template Alloc<MOMENT_T>(moment1_out), \
|
||||
moment2.data<MOMENT_T>(), \
|
||||
dev_ctx.template Alloc<MOMENT_T>(moment2_out), \
|
||||
amsgrad ? moment2_max->data<MOMENT_T>() : nullptr, \
|
||||
amsgrad ? dev_ctx.template Alloc<MOMENT_T>(moment2_max_out) \
|
||||
: nullptr, \
|
||||
param.numel(), \
|
||||
amsgrad); \
|
||||
}
|
||||
|
||||
#define DISPATCH_ADAMW_STYLE_COMPAT_KERNEL(MOMENT_T) \
|
||||
if (lr_on_cpu) { \
|
||||
AdamWLrAccessor<true> lr_accessor(lr_double); \
|
||||
if (beta_pow_on_cpu) { \
|
||||
const float sc = static_cast<float>( \
|
||||
std::round(std::log(static_cast<double>(beta1_pow.data<MT>()[0])) / \
|
||||
std::log(beta1_))); \
|
||||
AdamWBiasCorrAccessorCompat<MT, true> bias_corr_accessor( \
|
||||
beta1_, beta2_, sc); \
|
||||
LAUNCH_ADAMW_STYLE_KERNEL(MOMENT_T) \
|
||||
} else { \
|
||||
AdamWBiasCorrAccessorCompat<MT, false> bias_corr_accessor( \
|
||||
beta1_, beta2_, beta1_pow.data<MT>()); \
|
||||
LAUNCH_ADAMW_STYLE_KERNEL(MOMENT_T) \
|
||||
} \
|
||||
} else { \
|
||||
AdamWLrAccessor<false> lr_accessor(learning_rate.data<double>(), \
|
||||
lr_ratio); \
|
||||
if (beta_pow_on_cpu) { \
|
||||
const float sc = static_cast<float>( \
|
||||
std::round(std::log(static_cast<double>(beta1_pow.data<MT>()[0])) / \
|
||||
std::log(beta1_))); \
|
||||
AdamWBiasCorrAccessorCompat<MT, true> bias_corr_accessor( \
|
||||
beta1_, beta2_, sc); \
|
||||
LAUNCH_ADAMW_STYLE_KERNEL(MOMENT_T) \
|
||||
} else { \
|
||||
AdamWBiasCorrAccessorCompat<MT, false> bias_corr_accessor( \
|
||||
beta1_, beta2_, beta1_pow.data<MT>()); \
|
||||
LAUNCH_ADAMW_STYLE_KERNEL(MOMENT_T) \
|
||||
} \
|
||||
}
|
||||
|
||||
// This function is only reached when FLAGS_use_accuracy_compatible_kernel is
|
||||
// true (see AdamwDenseKernel), so only the torch-compatible dispatch exists.
|
||||
if (use_bfloat16_moments) {
|
||||
DISPATCH_ADAMW_STYLE_COMPAT_KERNEL(bfloat16)
|
||||
} else {
|
||||
DISPATCH_ADAMW_STYLE_COMPAT_KERNEL(MT)
|
||||
}
|
||||
#undef DISPATCH_ADAMW_STYLE_COMPAT_KERNEL
|
||||
#undef LAUNCH_ADAMW_STYLE_KERNEL
|
||||
|
||||
// Update beta_pow (same as original)
|
||||
if (!use_global_beta_pow) {
|
||||
if (beta_pow_on_cpu) {
|
||||
auto* beta1_pow_out_data = dev_ctx.template HostAlloc<MT>(beta1_pow_out);
|
||||
auto* beta2_pow_out_data = dev_ctx.template HostAlloc<MT>(beta2_pow_out);
|
||||
beta1_pow_out_data[0] = beta1_ * beta1_pow.data<MT>()[0];
|
||||
beta2_pow_out_data[0] = beta2_ * beta2_pow.data<MT>()[0];
|
||||
} else {
|
||||
UpdateBetaPowKernel<MT><<<1, 1, 0, dev_ctx.stream()>>>(
|
||||
beta1_,
|
||||
beta2_,
|
||||
beta1_pow.data<MT>(),
|
||||
beta2_pow.data<MT>(),
|
||||
dev_ctx.template Alloc<MT>(beta1_pow_out),
|
||||
dev_ctx.template Alloc<MT>(beta2_pow_out));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(adamw,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AdamwDenseKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {
|
||||
kernel->InputAt(2).SetDataType(phi::DataType::FLOAT64);
|
||||
kernel->InputAt(6).SetBackend(phi::Backend::ALL_BACKEND);
|
||||
kernel->InputAt(7).SetBackend(phi::Backend::ALL_BACKEND);
|
||||
kernel->InputAt(9).SetBackend(phi::Backend::ALL_BACKEND);
|
||||
|
||||
if (kernel_key.dtype() == phi::DataType::FLOAT16 ||
|
||||
kernel_key.dtype() == phi::DataType::BFLOAT16) {
|
||||
kernel->OutputAt(1).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(2).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(3).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(4).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(5).SetDataType(phi::DataType::FLOAT32);
|
||||
kernel->OutputAt(6).SetDataType(phi::DataType::FLOAT32);
|
||||
}
|
||||
kernel->OutputAt(4).SetBackend(phi::Backend::UNDEFINED);
|
||||
kernel->OutputAt(5).SetBackend(phi::Backend::UNDEFINED);
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/add_n_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/cuda/cuda_graph_with_memory_pool.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/common/memory_utils.h"
|
||||
#include "paddle/phi/kernels/impl/add_n_kernel_impl.h"
|
||||
namespace phi {
|
||||
|
||||
#define CEIL_DIV(x, y) (((x) + (y)-1) / (y))
|
||||
|
||||
template <class T>
|
||||
__global__ void SumArrayCUDAKernel(
|
||||
T **in, T *out, int64_t N, size_t in_size, bool read_dst) {
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
CUDA_KERNEL_LOOP_TYPE(idx, N, int64_t) {
|
||||
MT total(read_dst ? static_cast<MT>(out[idx]) : static_cast<MT>(0));
|
||||
for (int i = 0; i < in_size; ++i) {
|
||||
const T *tmp = in[i];
|
||||
if (tmp) {
|
||||
total += static_cast<MT>(tmp[idx]);
|
||||
}
|
||||
}
|
||||
out[idx] = static_cast<T>(total);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, class HALF>
|
||||
__global__ void SumArrayMixedTypeCUDAKernel(const T *in_0,
|
||||
void **in_others,
|
||||
T *out,
|
||||
int64_t N,
|
||||
size_t in_others_size,
|
||||
bool read_dst) {
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
CUDA_KERNEL_LOOP_TYPE(idx, N, int64_t) {
|
||||
MT total(read_dst ? static_cast<MT>(out[idx]) : static_cast<MT>(0));
|
||||
total += static_cast<MT>(in_0[idx]);
|
||||
for (int i = 0; i < in_others_size; ++i) {
|
||||
const HALF *tmp = static_cast<HALF *>(in_others[i]);
|
||||
if (tmp) {
|
||||
total += static_cast<MT>(tmp[idx]);
|
||||
}
|
||||
}
|
||||
out[idx] = static_cast<T>(total);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
__global__ void SumSelectedRowsCUDAKernel(T **sr_in_out,
|
||||
int64_t N,
|
||||
size_t rows) {
|
||||
CUDA_KERNEL_LOOP_TYPE(idx, N, int64_t) {
|
||||
for (int i = 0; i < 2 * rows; i += 2) {
|
||||
const T *tmp = sr_in_out[i];
|
||||
T *tmp_out = sr_in_out[i + 1];
|
||||
if (tmp && tmp_out) {
|
||||
tmp_out[idx] += tmp[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AddNKernel(const Context &dev_ctx,
|
||||
const std::vector<const TensorBase *> &x,
|
||||
DenseTensor *out) {
|
||||
if (out && out->numel() == 0) {
|
||||
dev_ctx.template Alloc<T>(out);
|
||||
return;
|
||||
}
|
||||
const size_t in_num = x.size();
|
||||
for (int i = 0; i < in_num; ++i) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
x[i]->valid() && x[i]->has_allocation(),
|
||||
true,
|
||||
common::errors::InvalidArgument(
|
||||
"This argument is invalid, %d-th tensor is uninitialized.", i));
|
||||
}
|
||||
|
||||
constexpr size_t theory_sm_threads = 1024;
|
||||
auto stream = dev_ctx.stream();
|
||||
|
||||
auto max_threads = dev_ctx.GetMaxPhysicalThreadCount();
|
||||
auto sm_count = max_threads / theory_sm_threads;
|
||||
size_t tile_size = 0;
|
||||
dim3 grids;
|
||||
dim3 blocks;
|
||||
|
||||
auto ComputeKernelParameter = [&](size_t length) {
|
||||
if (length >= max_threads)
|
||||
tile_size = 1024;
|
||||
else if (length < max_threads && length > sm_count * 128)
|
||||
tile_size = 512;
|
||||
else if (length <= sm_count * 128)
|
||||
tile_size = 256;
|
||||
grids = dim3(CEIL_DIV(length, tile_size), 1, 1);
|
||||
blocks = dim3(tile_size, 1, 1);
|
||||
};
|
||||
auto *out_ptr = dev_ctx.template Alloc<T>(out);
|
||||
bool in_place = false;
|
||||
|
||||
if (x.size() > 0 && x[0]->initialized() && DenseTensor::classof(x[0])) {
|
||||
if ((static_cast<const DenseTensor *>(x[0]))->data() == out->data()) {
|
||||
in_place = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Sum of two tensors
|
||||
if (in_num == 2 && DenseTensor::classof(x[0]) && DenseTensor::classof(x[1])) {
|
||||
auto &in_0 = *(static_cast<const DenseTensor *>(x[0]));
|
||||
auto &in_1 = *(static_cast<const DenseTensor *>(x[1]));
|
||||
int64_t length_0 = in_0.numel();
|
||||
int64_t length_1 = in_1.numel();
|
||||
if (length_0 && length_1 && in_0.IsInitialized() && in_1.IsInitialized()) {
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
auto result = EigenVector<T>::Flatten(*out);
|
||||
auto &place = *dev_ctx.eigen_device();
|
||||
auto in_0_e = EigenVector<T>::Flatten(in_0).template cast<MT>();
|
||||
auto in_1_e = EigenVector<T>::Flatten(in_1).template cast<MT>();
|
||||
result.device(place) = (in_0_e + in_1_e).template cast<T>();
|
||||
} else if (length_0 && in_0.IsInitialized()) {
|
||||
auto result = EigenVector<T>::Flatten(*out);
|
||||
auto &place = *dev_ctx.eigen_device();
|
||||
result.device(place) = EigenVector<T>::Flatten(in_0);
|
||||
} else if (length_1 && in_1.IsInitialized()) {
|
||||
auto result = EigenVector<T>::Flatten(*out);
|
||||
auto &place = *dev_ctx.eigen_device();
|
||||
result.device(place) = EigenVector<T>::Flatten(in_1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int start = in_place ? 1 : 0;
|
||||
if (!in_place) {
|
||||
funcs::SetConstant<GPUContext, T> constant_functor;
|
||||
constant_functor(dev_ctx, out, static_cast<T>(0));
|
||||
}
|
||||
|
||||
// Support mixed inputs for master grad accumulation
|
||||
// conditions:
|
||||
// 1. all inputs are DensorTensor and number >= 2
|
||||
// 2. the first tensor is fp32 type and the others are fp16/bf16 type
|
||||
if (in_num >= 2 && DenseTensor::classof(x[0]) &&
|
||||
x[0]->dtype() == DataType::FLOAT32 &&
|
||||
x[1]->dtype() != DataType::FLOAT32) {
|
||||
auto in_other_dtype = x[1]->dtype();
|
||||
int64_t numel = static_cast<const DenseTensor *>(x[0])->numel();
|
||||
bool all_dense_tensor = true;
|
||||
std::vector<const void *> in_data;
|
||||
const T *in_0 = static_cast<const DenseTensor *>(x[0])->data<T>();
|
||||
for (int i = 1; i < in_num; ++i) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
in_other_dtype,
|
||||
x[i]->dtype(),
|
||||
errors::InvalidArgument("The dtype of inputs should be the same, "
|
||||
"but received the dtype of input 1 is %s, "
|
||||
"input %d is %s",
|
||||
in_other_dtype,
|
||||
i,
|
||||
x[i]->dtype()));
|
||||
if (DenseTensor::classof(x[i])) {
|
||||
auto &in_i = *(static_cast<const DenseTensor *>(x[i]));
|
||||
if (in_i.IsInitialized()) {
|
||||
in_data.emplace_back(in_i.data());
|
||||
}
|
||||
} else {
|
||||
all_dense_tensor = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_dense_tensor && (in_other_dtype == DataType::BFLOAT16 ||
|
||||
in_other_dtype == DataType::FLOAT16)) {
|
||||
auto tmp_in_array = phi::memory_utils::Alloc(
|
||||
dev_ctx.GetPlace(), in_data.size() * sizeof(void *));
|
||||
size_t nbytes_in = in_data.size() * sizeof(void *);
|
||||
const void *stable_in = backends::gpu::RestoreHostMemIfCapturingCUDAGraph(
|
||||
reinterpret_cast<uint8_t *>(const_cast<void **>(in_data.data())),
|
||||
nbytes_in);
|
||||
memory_utils::Copy(dev_ctx.GetPlace(),
|
||||
tmp_in_array->ptr(),
|
||||
CPUPlace(),
|
||||
stable_in,
|
||||
nbytes_in,
|
||||
dev_ctx.stream());
|
||||
|
||||
void **in_array_data = reinterpret_cast<void **>(tmp_in_array->ptr());
|
||||
ComputeKernelParameter(numel);
|
||||
VLOG(4) << "Call SumArrayMixedTypeCUDAKernel";
|
||||
if (in_other_dtype == DataType::FLOAT16) {
|
||||
SumArrayMixedTypeCUDAKernel<T, phi::float16>
|
||||
<<<grids, blocks, 0, stream>>>(in_0,
|
||||
in_array_data,
|
||||
out->data<T>(),
|
||||
numel,
|
||||
in_data.size(),
|
||||
in_place);
|
||||
} else if (in_other_dtype == DataType::BFLOAT16) {
|
||||
SumArrayMixedTypeCUDAKernel<T, phi::bfloat16>
|
||||
<<<grids, blocks, 0, stream>>>(in_0,
|
||||
in_array_data,
|
||||
out->data<T>(),
|
||||
numel,
|
||||
in_data.size(),
|
||||
in_place);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<const T *> in_data;
|
||||
std::vector<int> selectrow_index;
|
||||
int64_t lod_length = 0;
|
||||
bool dst_write = false;
|
||||
for (int i = start; i < in_num; ++i) {
|
||||
if (DenseTensor::classof(x[i])) {
|
||||
auto &in_i = *(static_cast<const DenseTensor *>(x[i]));
|
||||
lod_length = in_i.numel();
|
||||
if (lod_length && in_i.IsInitialized()) {
|
||||
in_data.emplace_back(in_i.data<T>());
|
||||
}
|
||||
} else if (SelectedRows::classof(x[i])) {
|
||||
selectrow_index.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
// compute select rows separately.
|
||||
if (!selectrow_index.empty()) {
|
||||
std::vector<const T *> sr_in_out_data;
|
||||
size_t rows = 0;
|
||||
int64_t length = 0;
|
||||
for (auto index : selectrow_index) {
|
||||
auto &sr = *(static_cast<const SelectedRows *>(x[index]));
|
||||
auto &sr_value = sr.value();
|
||||
auto &sr_rows = sr.rows();
|
||||
|
||||
auto row_numel = sr_value.numel() / sr_rows.size();
|
||||
auto out_dims = out->dims();
|
||||
|
||||
PADDLE_ENFORCE_EQ(sr.height(),
|
||||
out_dims[0],
|
||||
errors::InvalidArgument(
|
||||
"The table height of input must be same as output, "
|
||||
"but received input height is %d"
|
||||
", output height is %d",
|
||||
sr.height(),
|
||||
out_dims[0]));
|
||||
PADDLE_ENFORCE_EQ(row_numel,
|
||||
out->numel() / sr.height(),
|
||||
errors::InvalidArgument(
|
||||
"The table width of input must be same as output, "
|
||||
"but received input width is %d"
|
||||
", output width is %d",
|
||||
row_numel,
|
||||
out->numel() / sr.height()));
|
||||
|
||||
auto *sr_data = sr_value.data<T>();
|
||||
auto *sr_out_data = out->data<T>();
|
||||
rows += sr_rows.size();
|
||||
length = row_numel;
|
||||
|
||||
for (size_t i = 0; i < sr_rows.size(); ++i) {
|
||||
sr_in_out_data.emplace_back(&sr_data[i * row_numel]);
|
||||
sr_in_out_data.emplace_back(&sr_out_data[sr_rows[i] * row_numel]);
|
||||
}
|
||||
}
|
||||
if (!sr_in_out_data.empty()) {
|
||||
auto tmp_sr_in_out_array = memory_utils::Alloc(
|
||||
dev_ctx.GetPlace(), sr_in_out_data.size() * sizeof(T *));
|
||||
|
||||
size_t nbytes_sr = sr_in_out_data.size() * sizeof(T *);
|
||||
const void *stable_sr = backends::gpu::RestoreHostMemIfCapturingCUDAGraph(
|
||||
reinterpret_cast<uint8_t *>(sr_in_out_data.data()), nbytes_sr);
|
||||
memory_utils::Copy(dev_ctx.GetPlace(),
|
||||
tmp_sr_in_out_array->ptr(),
|
||||
CPUPlace(),
|
||||
stable_sr,
|
||||
nbytes_sr,
|
||||
dev_ctx.stream());
|
||||
|
||||
T **sr_in_out_array_data =
|
||||
reinterpret_cast<T **>(tmp_sr_in_out_array->ptr());
|
||||
|
||||
ComputeKernelParameter(length);
|
||||
SumSelectedRowsCUDAKernel<T>
|
||||
<<<grids, blocks, 0, stream>>>(sr_in_out_array_data, length, rows);
|
||||
dst_write = true;
|
||||
}
|
||||
}
|
||||
// if indata not null, merge into one kernel call.
|
||||
if (!in_data.empty()) {
|
||||
auto tmp_in_array =
|
||||
memory_utils::Alloc(dev_ctx.GetPlace(), in_data.size() * sizeof(T *));
|
||||
|
||||
size_t nbytes_in2 = in_data.size() * sizeof(T *);
|
||||
const void *stable_in2 = backends::gpu::RestoreHostMemIfCapturingCUDAGraph(
|
||||
reinterpret_cast<uint8_t *>(const_cast<T **>(in_data.data())),
|
||||
nbytes_in2);
|
||||
memory_utils::Copy(dev_ctx.GetPlace(),
|
||||
tmp_in_array->ptr(),
|
||||
CPUPlace(),
|
||||
stable_in2,
|
||||
nbytes_in2,
|
||||
dev_ctx.stream());
|
||||
|
||||
T **in_array_data = reinterpret_cast<T **>(tmp_in_array->ptr());
|
||||
ComputeKernelParameter(lod_length);
|
||||
SumArrayCUDAKernel<T><<<grids, blocks, 0, stream>>>(in_array_data,
|
||||
out->data<T>(),
|
||||
lod_length,
|
||||
in_data.size(),
|
||||
dst_write | in_place);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(add_n,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AddNKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
phi::bfloat16,
|
||||
phi::float16,
|
||||
int64_t,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
|
||||
PD_REGISTER_KERNEL(add_n_array,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AddNArrayKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
phi::bfloat16,
|
||||
phi::float16,
|
||||
int64_t,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
@@ -0,0 +1,28 @@
|
||||
/* Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. */
|
||||
|
||||
#include "paddle/phi/kernels/addmm_grad_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/addmm_grad_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(addmm_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AddmmGradKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,28 @@
|
||||
/* Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. */
|
||||
|
||||
#include "paddle/phi/kernels/addmm_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/addmm_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(addmm,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AddmmKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,174 @@
|
||||
// Copyright (c) 2024 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/affine_channel_grad_kernel.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/cub.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, DataLayout layout, bool HasBias>
|
||||
__global__ static inline void KeAffineChannelCUDA(const T* x,
|
||||
const T* scale,
|
||||
const T* bias,
|
||||
const int C,
|
||||
const int64_t HxW,
|
||||
const int64_t num,
|
||||
T* y) {
|
||||
int64_t gid =
|
||||
static_cast<int64_t>(blockIdx.x) * static_cast<int64_t>(blockDim.x) +
|
||||
static_cast<int64_t>(threadIdx.x);
|
||||
int stride = blockDim.x * gridDim.x;
|
||||
for (int64_t i = gid; i < num; i += stride) {
|
||||
const int c = layout == DataLayout::NCHW ? i / HxW % C : i % C;
|
||||
if (HasBias) {
|
||||
y[i] = scale[c] * x[i] + bias[c];
|
||||
} else {
|
||||
y[i] = scale[c] * x[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, int BlockDim, DataLayout layout>
|
||||
__global__ void AffineChannelScaleBiasGradientCUDAKernel(const T* dy,
|
||||
const T* x,
|
||||
const int N,
|
||||
const int C,
|
||||
const int64_t HxW,
|
||||
T* dscale,
|
||||
T* dbias) {
|
||||
const int outer_size = C;
|
||||
const int64_t inner_size = HxW * N;
|
||||
typedef cub::BlockReduce<double, BlockDim> BlockReduce;
|
||||
__shared__ typename BlockReduce::TempStorage ds_storage;
|
||||
__shared__ typename BlockReduce::TempStorage db_storage;
|
||||
|
||||
for (int i = blockIdx.x; i < outer_size; i += gridDim.x) {
|
||||
T ds_sum = 0;
|
||||
T db_sum = 0;
|
||||
for (int64_t j = threadIdx.x; j < inner_size; j += blockDim.x) {
|
||||
const int64_t index = layout == DataLayout::NCHW
|
||||
? (j / HxW * C + i) * HxW + j % HxW
|
||||
: j * outer_size + i;
|
||||
ds_sum += dy[index] * x[index];
|
||||
db_sum += dy[index];
|
||||
}
|
||||
__syncthreads();
|
||||
auto ds_out =
|
||||
BlockReduce(ds_storage).Reduce(static_cast<double>(ds_sum), cub::Sum());
|
||||
auto db_out =
|
||||
BlockReduce(db_storage).Reduce(static_cast<double>(db_sum), cub::Sum());
|
||||
__syncthreads();
|
||||
if (threadIdx.x == 0) {
|
||||
dscale[i] = ds_out;
|
||||
dbias[i] = db_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AffineChannelGradCUDAKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x_in,
|
||||
const DenseTensor& scale_in,
|
||||
const DenseTensor& bias_in,
|
||||
const DenseTensor& out_grad,
|
||||
const std::string& data_layout,
|
||||
DenseTensor* x_grad,
|
||||
DenseTensor* scale_grad,
|
||||
DenseTensor* bias_grad) {
|
||||
auto* x = &x_in;
|
||||
auto* scale = &scale_in;
|
||||
auto* bias = &bias_in;
|
||||
auto* dy = &out_grad;
|
||||
|
||||
auto* dx = x_grad;
|
||||
auto* dscale = scale_grad;
|
||||
auto* dbias = bias_grad;
|
||||
|
||||
const DataLayout layout = StringToDataLayout(data_layout);
|
||||
|
||||
auto dims = dy->dims();
|
||||
const int64_t num = dy->numel();
|
||||
int64_t N = dims[0];
|
||||
int64_t C = layout == DataLayout::NCHW ? dims[1] : dims[dims.size() - 1];
|
||||
int64_t HxW = num / N / C;
|
||||
|
||||
const T* dy_d = dy->data<T>();
|
||||
const T* s_d = scale->data<T>();
|
||||
|
||||
T* dx_d = dx ? dev_ctx.template Alloc<T>(dx) : nullptr;
|
||||
T* ds_d = dscale ? dev_ctx.template Alloc<T>(dscale) : nullptr;
|
||||
T* db_d = dbias ? dev_ctx.template Alloc<T>(dbias) : nullptr;
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
const int block = 256;
|
||||
#else
|
||||
const int block = 1024;
|
||||
#endif // PADDLE_WITH_HIP
|
||||
int max_threads = dev_ctx.GetMaxPhysicalThreadCount();
|
||||
const int max_blocks = std::max(max_threads / block, 1);
|
||||
int grid1 = (num + block - 1) / block;
|
||||
int grid2 = std::min(static_cast<int>(C), max_blocks);
|
||||
|
||||
// NOTE(large-tensor): Kernel functions expect int for N and C parameters
|
||||
PADDLE_ENFORCE_LE_INT_MAX(N, "N");
|
||||
PADDLE_ENFORCE_LE_INT_MAX(C, "C");
|
||||
if (layout == DataLayout::NCHW) {
|
||||
if (dscale && dbias) {
|
||||
const T* x_d = x->data<T>();
|
||||
AffineChannelScaleBiasGradientCUDAKernel<T, block, DataLayout::NCHW>
|
||||
<<<grid2, block, 0, dev_ctx.stream()>>>(dy_d,
|
||||
x_d,
|
||||
static_cast<int>(N),
|
||||
static_cast<int>(C),
|
||||
HxW,
|
||||
ds_d,
|
||||
db_d);
|
||||
}
|
||||
if (dx) {
|
||||
KeAffineChannelCUDA<T, DataLayout::NCHW, false>
|
||||
<<<grid1, block, 0, dev_ctx.stream()>>>(
|
||||
dy_d, s_d, nullptr, static_cast<int>(C), HxW, num, dx_d);
|
||||
}
|
||||
} else {
|
||||
if (dscale && dbias) {
|
||||
const T* x_d = x->data<T>();
|
||||
AffineChannelScaleBiasGradientCUDAKernel<T, block, DataLayout::NHWC>
|
||||
<<<grid2, block, 0, dev_ctx.stream()>>>(dy_d,
|
||||
x_d,
|
||||
static_cast<int>(N),
|
||||
static_cast<int>(C),
|
||||
HxW,
|
||||
ds_d,
|
||||
db_d);
|
||||
}
|
||||
|
||||
if (dx) {
|
||||
KeAffineChannelCUDA<T, DataLayout::NHWC, false>
|
||||
<<<grid1, block, 0, dev_ctx.stream()>>>(
|
||||
dy_d, s_d, nullptr, static_cast<int>(C), HxW, num, dx_d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(affine_channel_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AffineChannelGradCUDAKernel,
|
||||
float,
|
||||
double) {}
|
||||
@@ -0,0 +1,102 @@
|
||||
// Copyright (c) 2024 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/affine_channel_kernel.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/cub.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, DataLayout layout, bool HasBias>
|
||||
__global__ static inline void KeAffineChannelCUDA(const T* x,
|
||||
const T* scale,
|
||||
const T* bias,
|
||||
const int C,
|
||||
const int64_t HxW,
|
||||
const int64_t num,
|
||||
T* y) {
|
||||
int64_t gid =
|
||||
static_cast<int64_t>(blockIdx.x) * static_cast<int64_t>(blockDim.x) +
|
||||
static_cast<int64_t>(threadIdx.x);
|
||||
int stride = blockDim.x * gridDim.x;
|
||||
for (int64_t i = gid; i < num; i += stride) {
|
||||
const int c = layout == DataLayout::NCHW ? i / HxW % C : i % C;
|
||||
if (HasBias) {
|
||||
y[i] = scale[c] * x[i] + bias[c];
|
||||
} else {
|
||||
y[i] = scale[c] * x[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AffineChannelCUDAKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x_in,
|
||||
const DenseTensor& scale_in,
|
||||
const DenseTensor& bias_in,
|
||||
const std::string& data_layout,
|
||||
DenseTensor* out) {
|
||||
auto* x = &x_in;
|
||||
auto* scale = &scale_in;
|
||||
auto* bias = &bias_in;
|
||||
|
||||
auto* y = out;
|
||||
dev_ctx.template Alloc<T>(y);
|
||||
|
||||
const DataLayout layout = StringToDataLayout(data_layout);
|
||||
|
||||
auto dims = x->dims();
|
||||
const int64_t num = x->numel();
|
||||
int64_t N = dims[0];
|
||||
int64_t C = layout == DataLayout::NCHW ? dims[1] : dims[dims.size() - 1];
|
||||
int64_t HxW = num / N / C;
|
||||
|
||||
const T* x_d = x->data<T>();
|
||||
const T* scale_d = scale->data<T>();
|
||||
const T* bias_d = bias->data<T>();
|
||||
T* y_d = y->data<T>();
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
int block = 256;
|
||||
#else
|
||||
int block = 1024;
|
||||
#endif // PADDLE_WITH_HIP
|
||||
int grid = (num + block - 1) / block;
|
||||
|
||||
int max_threads = dev_ctx.GetMaxPhysicalThreadCount();
|
||||
grid = std::min(std::max(max_threads / block, 1), grid);
|
||||
|
||||
// NOTE(large-tensor): KeAffineChannelCUDA function signature uses int for C
|
||||
// parameter
|
||||
PADDLE_ENFORCE_LE_INT_MAX(C, "C");
|
||||
if (layout == DataLayout::NCHW) {
|
||||
KeAffineChannelCUDA<T, DataLayout::NCHW, true>
|
||||
<<<grid, block, 0, dev_ctx.stream()>>>(
|
||||
x_d, scale_d, bias_d, static_cast<int>(C), HxW, num, y_d);
|
||||
} else {
|
||||
KeAffineChannelCUDA<T, DataLayout::NHWC, true>
|
||||
<<<grid, block, 0, dev_ctx.stream()>>>(
|
||||
x_d, scale_d, bias_d, static_cast<int>(C), HxW, num, y_d);
|
||||
}
|
||||
}
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(affine_channel,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AffineChannelCUDAKernel,
|
||||
float,
|
||||
double) {}
|
||||
@@ -0,0 +1,178 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paddle/phi/kernels/affine_grid_grad_kernel.h"
|
||||
|
||||
#include "glog/logging.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_device_function.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/common/int_array.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/bmm_kernel.h"
|
||||
#include "paddle/phi/kernels/full_kernel.h"
|
||||
#include "paddle/phi/kernels/funcs/affine_grid_utils.h"
|
||||
#include "paddle/phi/kernels/transpose_kernel.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AffineGridGrad4DCUDAKernel(const Context& dev_ctx,
|
||||
const DenseTensor& output_grad,
|
||||
const IntArray& outputShape,
|
||||
bool align_corners,
|
||||
DenseTensor* input_grad) {
|
||||
// The shape of the output grad is [N, H, W, 2]
|
||||
auto grad_grid_dims = output_grad.dims();
|
||||
int64_t n = grad_grid_dims[0];
|
||||
int64_t h = grad_grid_dims[1];
|
||||
int64_t w = grad_grid_dims[2];
|
||||
|
||||
// The shape of input_grad (theta gradient) should be [N, 2, 3]
|
||||
input_grad->Resize({n, 2, 3});
|
||||
T* grad_theta_data = dev_ctx.template Alloc<T>(input_grad);
|
||||
|
||||
if (output_grad.numel() == 0) {
|
||||
Full<T, Context>(dev_ctx, input_grad->dims(), 0, input_grad);
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Directly create the basic grid using the same kernel as the forward
|
||||
// direction
|
||||
DenseTensor base_grid;
|
||||
base_grid.Resize({n, h, w, 3});
|
||||
T* base_grid_data = dev_ctx.template Alloc<T>(&base_grid);
|
||||
|
||||
funcs::CreateBaseGridKernel_4D<T, Context>(
|
||||
dev_ctx, base_grid_data, n, h, w, align_corners);
|
||||
|
||||
// 2. Reshaping base_grid to [N, H * W, 3]
|
||||
DenseTensor base_grid_reshaped;
|
||||
base_grid_reshaped.ShareDataWith(base_grid);
|
||||
base_grid_reshaped.Resize({n, h * w, 3});
|
||||
|
||||
// 3. Transposition base_grid: [N, H * W, 3] ->[N, 3, H * W]
|
||||
DenseTensor base_grid_transposed;
|
||||
base_grid_transposed.Resize({n, 3, h * w});
|
||||
TransposeKernel<T, Context>(
|
||||
dev_ctx, base_grid_reshaped, {0, 2, 1}, &base_grid_transposed);
|
||||
|
||||
// 4. Reshaping Output_grad to [N, H * W, 2]
|
||||
DenseTensor grad_grid_reshaped;
|
||||
grad_grid_reshaped.ShareDataWith(output_grad);
|
||||
grad_grid_reshaped.Resize({n, h * w, 2});
|
||||
|
||||
// 5. Batch matrix multiplication: [N, 3, H * W] x [N, H * W, 2]=[N, 3, 2]
|
||||
DenseTensor grad_theta_temp;
|
||||
grad_theta_temp.Resize({n, 3, 2});
|
||||
|
||||
BmmKernel<T, Context>(
|
||||
dev_ctx, base_grid_transposed, grad_grid_reshaped, &grad_theta_temp);
|
||||
|
||||
// 6. Transposition yields the final result: [N, 3, 2] ->[N, 2, 3]
|
||||
TransposeKernel<T, Context>(dev_ctx, grad_theta_temp, {0, 2, 1}, input_grad);
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AffineGridGrad5DCUDAKernel(const Context& dev_ctx,
|
||||
const DenseTensor& output_grad,
|
||||
const IntArray& outputShape,
|
||||
bool align_corners,
|
||||
DenseTensor* input_grad) {
|
||||
// The shape of the output grad is [N, D, H, W, 3]
|
||||
auto grad_grid_dims = output_grad.dims();
|
||||
int64_t n = grad_grid_dims[0];
|
||||
int64_t d = grad_grid_dims[1];
|
||||
int64_t h = grad_grid_dims[2];
|
||||
int64_t w = grad_grid_dims[3];
|
||||
|
||||
// The shape of input_grad (theta gradient) should be [N, 3, 4]
|
||||
input_grad->Resize({n, 3, 4});
|
||||
T* grad_theta_data = dev_ctx.template Alloc<T>(input_grad);
|
||||
|
||||
if (output_grad.numel() == 0) {
|
||||
Full<T, Context>(dev_ctx, input_grad->dims(), 0, input_grad);
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Directly create the basic grid using the same kernel as the forward
|
||||
// direction
|
||||
DenseTensor base_grid;
|
||||
base_grid.Resize({n, d, h, w, 4});
|
||||
T* base_grid_data = dev_ctx.template Alloc<T>(&base_grid);
|
||||
|
||||
funcs::CreateBaseGridKernel_5D<T, Context>(
|
||||
dev_ctx, base_grid_data, n, d, h, w, align_corners);
|
||||
|
||||
// 2. Reshaping base_grid to [N, D * H * W, 4]
|
||||
DenseTensor base_grid_reshaped;
|
||||
base_grid_reshaped.ShareDataWith(base_grid);
|
||||
base_grid_reshaped.Resize({n, d * h * w, 4});
|
||||
|
||||
// 3. Transpose base_grid:[N,D*H*W,4]->[N,4,D*H*W]
|
||||
DenseTensor base_grid_transposed;
|
||||
base_grid_transposed.Resize({n, 4, d * h * w});
|
||||
TransposeKernel<T, Context>(
|
||||
dev_ctx, base_grid_reshaped, {0, 2, 1}, &base_grid_transposed);
|
||||
|
||||
// 4. Reshaping Output_grad to [N, D * H * W, 3]
|
||||
DenseTensor grad_grid_reshaped;
|
||||
grad_grid_reshaped.ShareDataWith(output_grad);
|
||||
grad_grid_reshaped.Resize({n, d * h * w, 3});
|
||||
|
||||
// 5. Batch matrix multiplication: [N, 4, D * H * W] x [N, D * H * W, 3]=[N,
|
||||
// 4, 3]
|
||||
DenseTensor grad_theta_temp;
|
||||
grad_theta_temp.Resize({n, 4, 3});
|
||||
|
||||
BmmKernel<T, Context>(
|
||||
dev_ctx, base_grid_transposed, grad_grid_reshaped, &grad_theta_temp);
|
||||
|
||||
// 6. Transposition yields the final result: [N, 4, 3] ->[N, 3, 4]
|
||||
TransposeKernel<T, Context>(dev_ctx, grad_theta_temp, {0, 2, 1}, input_grad);
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AffineGridGradCUDAKernel(const Context& dev_ctx,
|
||||
const DenseTensor& input,
|
||||
const IntArray& outputShape,
|
||||
bool align_corners,
|
||||
DenseTensor* output) {
|
||||
auto* theta = &input;
|
||||
auto theta_size = theta->dims().size();
|
||||
if (output->numel() == 0 || input.numel() == 0) {
|
||||
dev_ctx.template Alloc<T>(output);
|
||||
funcs::SetConstant<GPUContext, T>()(dev_ctx, output, static_cast<T>(0));
|
||||
return;
|
||||
}
|
||||
if (theta_size == 4) {
|
||||
AffineGridGrad4DCUDAKernel<T, Context>(
|
||||
dev_ctx, input, outputShape, align_corners, output);
|
||||
} else {
|
||||
AffineGridGrad5DCUDAKernel<T, Context>(
|
||||
dev_ctx, input, outputShape, align_corners, output);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(affine_grid_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AffineGridGradCUDAKernel,
|
||||
float,
|
||||
double){};
|
||||
@@ -0,0 +1,144 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paddle/phi/kernels/affine_grid_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/all_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_device_function.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/common/int_array.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/bmm_kernel.h"
|
||||
#include "paddle/phi/kernels/full_kernel.h"
|
||||
#include "paddle/phi/kernels/funcs/affine_grid_utils.h"
|
||||
#include "paddle/phi/kernels/transpose_kernel.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AffineGrid4DCUDAKernel(const Context& dev_ctx,
|
||||
const DenseTensor& input,
|
||||
const IntArray& outputShape,
|
||||
bool align_corners,
|
||||
DenseTensor* output) {
|
||||
auto* theta = &input;
|
||||
int64_t n = theta->dims()[0];
|
||||
auto& size_attr = outputShape.GetData();
|
||||
int64_t h = size_attr[2];
|
||||
int64_t w = size_attr[3];
|
||||
|
||||
if (input.numel() == 0) {
|
||||
output->Resize({n, h, w, 2});
|
||||
Full<T, Context>(dev_ctx, output->dims(), 0, output);
|
||||
return;
|
||||
}
|
||||
|
||||
// Directly create the base mesh
|
||||
DenseTensor base_grid;
|
||||
base_grid.Resize({n, h, w, 3});
|
||||
T* base_grid_data = dev_ctx.template Alloc<T>(&base_grid);
|
||||
|
||||
funcs::CreateBaseGridKernel_4D<T, Context>(
|
||||
dev_ctx, base_grid_data, n, h, w, align_corners);
|
||||
|
||||
// Apply affine transformation
|
||||
DenseTensor base_grid_new;
|
||||
base_grid_new.ShareDataWith(base_grid);
|
||||
base_grid_new.Resize({n, h * w, 3});
|
||||
|
||||
// Transpose theta: [N, 2, 3] -> [N, 3, 2]
|
||||
DenseTensor theta_transposed;
|
||||
theta_transposed.Resize({n, 3, 2});
|
||||
TransposeKernel<T, Context>(dev_ctx, input, {0, 2, 1}, &theta_transposed);
|
||||
|
||||
DenseTensor grid_flat;
|
||||
grid_flat.Resize({n, h * w, 2});
|
||||
BmmKernel<T, Context>(dev_ctx, base_grid_new, theta_transposed, &grid_flat);
|
||||
|
||||
// Reshaping Output
|
||||
output->ShareDataWith(grid_flat);
|
||||
output->Resize({n, h, w, 2});
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AffineGrid5DCUDAKernel(const Context& dev_ctx,
|
||||
const DenseTensor& input,
|
||||
const IntArray& outputShape,
|
||||
bool align_corners,
|
||||
DenseTensor* output) {
|
||||
auto* theta = &input;
|
||||
int64_t n = theta->dims()[0];
|
||||
auto& size_attr = outputShape.GetData();
|
||||
int64_t d = size_attr[2]; // depth
|
||||
int64_t h = size_attr[3]; // height
|
||||
int64_t w = size_attr[4]; // width
|
||||
|
||||
if (input.numel() == 0) {
|
||||
output->Resize({n, d, h, w, 3});
|
||||
Full<T, Context>(dev_ctx, output->dims(), 0, output);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a basic grid
|
||||
DenseTensor base_grid;
|
||||
base_grid.Resize({n, d, h, w, 4});
|
||||
T* base_grid_data = dev_ctx.template Alloc<T>(&base_grid);
|
||||
|
||||
funcs::CreateBaseGridKernel_5D<T, Context>(
|
||||
dev_ctx, base_grid_data, n, d, h, w, align_corners);
|
||||
|
||||
// Apply affine transformation
|
||||
DenseTensor base_grid_new;
|
||||
base_grid_new.ShareDataWith(base_grid);
|
||||
base_grid_new.Resize({n, d * h * w, 4});
|
||||
|
||||
// Transpose theta: [N, 3, 4] -> [N, 4, 3]
|
||||
DenseTensor theta_transposed;
|
||||
theta_transposed.Resize({n, 4, 3});
|
||||
TransposeKernel<T, Context>(dev_ctx, input, {0, 2, 1}, &theta_transposed);
|
||||
|
||||
// Perform batch matrix multiplication
|
||||
DenseTensor grid_flat;
|
||||
grid_flat.Resize({n, d * h * w, 3});
|
||||
BmmKernel<T, Context>(dev_ctx, base_grid_new, theta_transposed, &grid_flat);
|
||||
|
||||
// Reshaping Output
|
||||
output->ShareDataWith(grid_flat);
|
||||
output->Resize({n, d, h, w, 3});
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AffineGridCUDAKernel(const Context& dev_ctx,
|
||||
const DenseTensor& input,
|
||||
const IntArray& outputShape,
|
||||
bool align_corners,
|
||||
DenseTensor* output) {
|
||||
auto* theta = &input;
|
||||
int64_t theta_h = theta->dims()[1];
|
||||
if (theta_h == 2) {
|
||||
AffineGrid4DCUDAKernel<T, Context>(
|
||||
dev_ctx, input, outputShape, align_corners, output);
|
||||
} else {
|
||||
AffineGrid5DCUDAKernel<T, Context>(
|
||||
dev_ctx, input, outputShape, align_corners, output);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(
|
||||
affine_grid, GPU, ALL_LAYOUT, phi::AffineGridCUDAKernel, float, double){};
|
||||
@@ -0,0 +1,75 @@
|
||||
// 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/all_gather_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/all_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
#include "paddle/phi/core/distributed/nccl_comm_context.h"
|
||||
#endif
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AllGatherKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
int nranks,
|
||||
DenseTensor* out) {
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
auto out_dims = x.dims();
|
||||
out_dims[0] *= nranks;
|
||||
out->Resize(out_dims);
|
||||
dev_ctx.template Alloc<T>(out);
|
||||
|
||||
auto comm_ctx =
|
||||
static_cast<distributed::NCCLCommContext*>(dev_ctx.GetCommContext());
|
||||
PADDLE_ENFORCE_NE(
|
||||
comm_ctx,
|
||||
nullptr,
|
||||
errors::Unavailable("NCCLCommContext is nullptr, collective op should "
|
||||
"has ring_id attr."));
|
||||
PADDLE_ENFORCE_EQ(
|
||||
nranks,
|
||||
comm_ctx->GetSize(),
|
||||
errors::InvalidArgument(
|
||||
"nranks: %s should equal to %s", nranks, comm_ctx->GetSize()));
|
||||
|
||||
gpuStream_t stream = dev_ctx.stream();
|
||||
comm_ctx->AllGather(out, x, stream);
|
||||
#else
|
||||
PADDLE_THROW(
|
||||
errors::PreconditionNotMet("PaddlePaddle should compile with GPU."));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(all_gather,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AllGatherKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
uint8_t,
|
||||
int8_t,
|
||||
int16_t,
|
||||
int64_t,
|
||||
bool,
|
||||
phi::bfloat16,
|
||||
phi::float16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
@@ -0,0 +1,98 @@
|
||||
// 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/all_reduce_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/all_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
#include "paddle/phi/core/distributed/nccl_comm_context.h"
|
||||
#endif
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AllReduceKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
int reduce_type,
|
||||
DenseTensor* out) {
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
out->Resize(x.dims());
|
||||
dev_ctx.template Alloc<T>(out);
|
||||
|
||||
auto comm_ctx =
|
||||
static_cast<distributed::NCCLCommContext*>(dev_ctx.GetCommContext());
|
||||
PADDLE_ENFORCE_NE(
|
||||
comm_ctx,
|
||||
nullptr,
|
||||
errors::Unavailable("NCCLCommContext is nullptr, collective op should "
|
||||
"has ring_id attr."));
|
||||
gpuStream_t stream = dev_ctx.stream();
|
||||
PADDLE_ENFORCE_NOT_NULL(stream,
|
||||
errors::NotFound("Should initialize NCCL firstly."));
|
||||
|
||||
ncclRedOp_t red_type = ncclSum;
|
||||
switch (static_cast<ReduceType>(reduce_type)) {
|
||||
case ReduceType::kRedSum:
|
||||
red_type = ncclSum;
|
||||
break;
|
||||
case ReduceType::kRedMax:
|
||||
red_type = ncclMax;
|
||||
break;
|
||||
case ReduceType::kRedMin:
|
||||
red_type = ncclMin;
|
||||
break;
|
||||
case ReduceType::kRedProd:
|
||||
red_type = ncclProd;
|
||||
break;
|
||||
#if NCCL_VERSION_CODE >= 21000
|
||||
case ReduceType::kRedAvg:
|
||||
red_type = ncclAvg;
|
||||
break;
|
||||
#endif
|
||||
case ReduceType::kRedAll:
|
||||
// NOTE(zhonghui): There is no reduce_all type of ncclRedOp_t, just use
|
||||
// min to replace
|
||||
red_type = ncclMin;
|
||||
break;
|
||||
case ReduceType::kRedAny:
|
||||
// NOTE(ooooo): There is no reduce_any type of ncclRedOp_t, just use
|
||||
// max to replace
|
||||
red_type = ncclMax;
|
||||
break;
|
||||
}
|
||||
comm_ctx->AllReduce(out, x, red_type, stream);
|
||||
#else
|
||||
PADDLE_THROW(
|
||||
errors::PreconditionNotMet("PaddlePaddle should compile with GPU."));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(all_reduce,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AllReduceKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
bool,
|
||||
int8_t,
|
||||
uint8_t,
|
||||
int16_t,
|
||||
int64_t,
|
||||
phi::bfloat16,
|
||||
phi::float16) {}
|
||||
@@ -0,0 +1,94 @@
|
||||
// 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/all_to_all_kernel.h"
|
||||
#include "glog/logging.h"
|
||||
|
||||
#include "paddle/phi/backends/all_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
#include "paddle/phi/core/distributed/nccl_comm_context.h"
|
||||
#include "paddle/phi/core/distributed/utils.h"
|
||||
#endif
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AllToAllKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
DenseTensor* out) {
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
auto x_dims = x.dims();
|
||||
out->Resize(x_dims);
|
||||
dev_ctx.template Alloc<T>(out);
|
||||
|
||||
auto comm_ctx =
|
||||
static_cast<distributed::NCCLCommContext*>(dev_ctx.GetCommContext());
|
||||
PADDLE_ENFORCE_NE(
|
||||
comm_ctx,
|
||||
nullptr,
|
||||
errors::Unavailable("NCCLCommContext is nullptr, collective op should "
|
||||
"has ring_id attr."));
|
||||
gpuStream_t stream = dev_ctx.stream();
|
||||
PADDLE_ENFORCE_NOT_NULL(stream,
|
||||
errors::NotFound("Should initialize NCCL firstly."));
|
||||
|
||||
int nranks = comm_ctx->GetSize();
|
||||
int64_t send_numel = x.numel() / nranks;
|
||||
size_t offset = 0;
|
||||
|
||||
PADDLE_ENFORCE_EQ(
|
||||
x_dims[0] % nranks,
|
||||
0,
|
||||
errors::InvalidArgument(
|
||||
"The first dimension size (%d) of the input tensor must be "
|
||||
"divisible by the number of ranks (%d).",
|
||||
x_dims[0],
|
||||
nranks));
|
||||
|
||||
comm_ctx->GroupStart();
|
||||
|
||||
const auto* send_buf = x.data<T>();
|
||||
auto* recv_buf = out->data<T>();
|
||||
for (auto i = 0; i < nranks; ++i) {
|
||||
auto send_buf = distributed::GetPartialTensor(x, offset, send_numel);
|
||||
comm_ctx->Send(send_buf, send_numel, i, stream);
|
||||
auto recv_buf = distributed::GetPartialTensor(*out, offset, send_numel);
|
||||
comm_ctx->Recv(&recv_buf, send_numel, i, stream);
|
||||
offset += send_numel;
|
||||
}
|
||||
comm_ctx->GroupEnd();
|
||||
#else
|
||||
PADDLE_THROW(
|
||||
errors::PreconditionNotMet("PaddlePaddle should compile with GPU."));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(all_to_all,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AllToAllKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int8_t,
|
||||
uint8_t,
|
||||
int16_t,
|
||||
int64_t,
|
||||
bool,
|
||||
phi::bfloat16,
|
||||
phi::float16) {}
|
||||
@@ -0,0 +1,131 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/allclose_kernel.h"
|
||||
|
||||
#include <type_traits>
|
||||
#include "glog/logging.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_launch_config.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/common/data_type.h"
|
||||
#include "paddle/phi/core/enforce.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/full_kernel.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename IndexType>
|
||||
__global__ void AllcloseCUDAKernel(const T* in_data,
|
||||
const T* other_data,
|
||||
const double rtol,
|
||||
const double atol,
|
||||
bool equal_nan,
|
||||
IndexType num,
|
||||
bool* out_data) {
|
||||
unsigned int idx = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
bool val;
|
||||
using BaseMT = typename MPTypeTrait<T>::Type;
|
||||
|
||||
using MT = typename std::conditional<std::is_same<T, int32_t>::value ||
|
||||
std::is_same<T, int64_t>::value ||
|
||||
std::is_same<T, bool>::value,
|
||||
double,
|
||||
BaseMT>::type;
|
||||
|
||||
for (IndexType i = idx; i < num; i += blockDim.x * gridDim.x) {
|
||||
const MT a = static_cast<MT>(in_data[i]);
|
||||
const MT b = static_cast<MT>(other_data[i]);
|
||||
if (isnan(a) || isnan(b)) {
|
||||
val = equal_nan && isnan(a) == isnan(b);
|
||||
} else {
|
||||
MT left = (a > b ? a - b : b - a);
|
||||
MT right = atol + (b > 0 ? rtol * b : (-rtol) * b);
|
||||
MT diff = (left > right ? left - right : right - left);
|
||||
val = a == b || left <= right || diff <= 1e-15;
|
||||
}
|
||||
if (!val) *out_data = false;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AllCloseKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const DenseTensor& y,
|
||||
const Scalar& rtol,
|
||||
const Scalar& atol,
|
||||
bool equal_nan,
|
||||
DenseTensor* out) {
|
||||
if (x.numel() == 0 || y.numel() == 0) {
|
||||
Full<bool, Context>(dev_ctx, out->dims(), true, out);
|
||||
return;
|
||||
}
|
||||
double rtol_v, atol_v;
|
||||
if (rtol.dtype() == DataType::FLOAT64) {
|
||||
rtol_v = rtol.to<double>();
|
||||
} else if (rtol.dtype() == DataType::FLOAT32) {
|
||||
rtol_v = rtol.to<float>();
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"Input (Rtol) type must be double or float, but get %s.",
|
||||
rtol.dtype()));
|
||||
}
|
||||
if (atol.dtype() == DataType::FLOAT64) {
|
||||
atol_v = atol.to<double>();
|
||||
} else if (atol.dtype() == DataType::FLOAT32) {
|
||||
atol_v = atol.to<float>();
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"Input (Atol) type must be double or float, but get %s.",
|
||||
atol.dtype()));
|
||||
}
|
||||
VLOG(3) << "rtol and atol is : " << rtol_v << " " << atol_v;
|
||||
const T* in_data = x.data<T>();
|
||||
const T* other_data = y.data<T>();
|
||||
bool* out_data = dev_ctx.template Alloc<bool>(out);
|
||||
|
||||
int64_t num = x.numel();
|
||||
const int vec_size = 4;
|
||||
auto config = backends::gpu::GetGpuLaunchConfig1D(dev_ctx, num, vec_size);
|
||||
uint32_t grid = config.block_per_grid.x;
|
||||
uint32_t block = config.thread_per_block.x;
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hipMemset(out_data, true, sizeof(bool));
|
||||
#else
|
||||
cudaMemset(out_data, true, sizeof(bool));
|
||||
#endif
|
||||
if (num > std::numeric_limits<int32_t>::max()) {
|
||||
AllcloseCUDAKernel<T, int64_t><<<grid, block, 0, dev_ctx.stream()>>>(
|
||||
in_data, other_data, rtol_v, atol_v, equal_nan, num, out_data);
|
||||
} else {
|
||||
AllcloseCUDAKernel<T, int32_t><<<grid, block, 0, dev_ctx.stream()>>>(
|
||||
in_data, other_data, rtol_v, atol_v, equal_nan, num, out_data);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(allclose,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AllCloseKernel,
|
||||
float,
|
||||
double,
|
||||
bool,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16) {
|
||||
kernel->OutputAt(0).SetDataType(phi::DataType::BOOL);
|
||||
}
|
||||
@@ -0,0 +1,386 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/amp_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/cuda/cuda_graph_with_memory_pool.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/common/memory_utils.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/empty_kernel.h"
|
||||
#include "paddle/phi/kernels/impl/amp_kernel_impl.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
// Utils
|
||||
|
||||
template <typename T>
|
||||
__global__ void InverseAndMemset(const T* s, T* o, bool* found_inf) {
|
||||
*o = 1.0 / *s;
|
||||
*found_inf = false;
|
||||
}
|
||||
|
||||
template <typename T, typename MT>
|
||||
__global__ void CheckFiniteAndUnscale(const T** xs,
|
||||
const MT* scale,
|
||||
int64_t size,
|
||||
int64_t* starts,
|
||||
bool* found_inf,
|
||||
T** outs) {
|
||||
const int64_t tid = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
|
||||
// copy starts array from global memory to shared memory
|
||||
extern __shared__ int64_t s_starts[];
|
||||
for (int64_t i = threadIdx.x; i <= size; i += blockDim.x) {
|
||||
s_starts[i] = starts[i];
|
||||
}
|
||||
__syncthreads();
|
||||
|
||||
const int64_t num = s_starts[size];
|
||||
int xs_index = 0;
|
||||
bool local_found_inf = false;
|
||||
const MT local_scale = *scale;
|
||||
for (int64_t idx = tid; idx < num; idx += gridDim.x * blockDim.x) {
|
||||
// get the "out" index of "id"
|
||||
// For example:
|
||||
// idx = 15, starts = [0, 10, 10, 20, 30]
|
||||
// because 10 <= idx < 20 ==>
|
||||
// the idx element locate in the 3rd tensor (notice the 2nd tensor size is
|
||||
// 0)
|
||||
int next_xs_index = xs_index;
|
||||
while (idx >= s_starts[next_xs_index]) next_xs_index++;
|
||||
xs_index = next_xs_index - 1;
|
||||
|
||||
// get in data and out data
|
||||
const T* in = xs[xs_index];
|
||||
T* out = outs[xs_index];
|
||||
int64_t in_idx = idx - s_starts[xs_index];
|
||||
|
||||
// Unscale
|
||||
MT val = static_cast<MT>(in[in_idx]) * local_scale;
|
||||
T narrow_val = static_cast<T>(val);
|
||||
out[in_idx] = narrow_val;
|
||||
|
||||
// CheckFinite
|
||||
if (!isfinite(narrow_val)) {
|
||||
local_found_inf = true;
|
||||
}
|
||||
}
|
||||
if (local_found_inf) {
|
||||
*found_inf = true;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename FoundNanInfFlagT>
|
||||
__global__ void GpuUpdateLossScaling(const FoundNanInfFlagT found_inf_data,
|
||||
const T* pre_loss_scaling_data,
|
||||
const int* good_in_data,
|
||||
const int* bad_in_data,
|
||||
const int incr_every_n_steps,
|
||||
const int decr_every_n_nan_or_inf,
|
||||
const float incr_ratio,
|
||||
const float decr_ratio,
|
||||
T* updated_loss_scaling_data,
|
||||
int* good_out_data,
|
||||
int* bad_out_data) {
|
||||
Update<T>(found_inf_data,
|
||||
pre_loss_scaling_data,
|
||||
good_in_data,
|
||||
bad_in_data,
|
||||
incr_every_n_steps,
|
||||
decr_every_n_nan_or_inf,
|
||||
incr_ratio,
|
||||
decr_ratio,
|
||||
updated_loss_scaling_data,
|
||||
good_out_data,
|
||||
bad_out_data);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void FusedFillIf(T** outs,
|
||||
const size_t xs_size,
|
||||
const int64_t* starts,
|
||||
const T value,
|
||||
const bool* has_inf) {
|
||||
if (!(*has_inf)) return;
|
||||
|
||||
const int tid = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
|
||||
// copy starts array from global memory to shared memory
|
||||
extern __shared__ int64_t s_starts[];
|
||||
for (size_t i = threadIdx.x; i <= xs_size; i += blockDim.x) {
|
||||
s_starts[i] = starts[i];
|
||||
}
|
||||
__syncthreads();
|
||||
|
||||
const int64_t total_num = s_starts[xs_size];
|
||||
int out_index = 0;
|
||||
|
||||
for (int64_t id = tid; id < total_num; id += blockDim.x * gridDim.x) {
|
||||
// get the "out" index of "id"
|
||||
// For example:
|
||||
// id = 15, starts = [0, 10, 10, 20, 30]
|
||||
// because 10 <= id < 20 ==>
|
||||
// the id element locate in the 3rd tensor (notice the 2nd tensor size is 0)
|
||||
int next_out_index = out_index;
|
||||
while (id >= s_starts[next_out_index]) next_out_index++;
|
||||
out_index = next_out_index - 1;
|
||||
|
||||
// get data pointer and index
|
||||
T* out_data = outs[out_index];
|
||||
int64_t idx = id - s_starts[out_index];
|
||||
|
||||
// set value
|
||||
out_data[idx] = value;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class LazyZeros<GPUContext, T> {
|
||||
public:
|
||||
void operator()(const GPUContext& dev_ctx,
|
||||
const bool* found_inf_data,
|
||||
const std::vector<const DenseTensor*>& xs,
|
||||
const std::vector<DenseTensor*>& outs) {
|
||||
size_t xs_size = xs.size();
|
||||
if (xs_size == 0) return;
|
||||
|
||||
const auto& cpu_place = CPUPlace();
|
||||
// alloc each tensor's start index and copy to device
|
||||
auto h_in_starts_mem =
|
||||
memory_utils::Alloc(cpu_place, (xs_size + 1) * sizeof(int64_t));
|
||||
int64_t* h_starts = reinterpret_cast<int64_t*>(h_in_starts_mem->ptr());
|
||||
|
||||
auto d_in_starts_mem = memory_utils::Alloc(
|
||||
dev_ctx.GetPlace(),
|
||||
(xs_size + 1) * sizeof(int64_t),
|
||||
Stream(reinterpret_cast<StreamId>(dev_ctx.stream())));
|
||||
int64_t* d_starts = reinterpret_cast<int64_t*>(d_in_starts_mem->ptr());
|
||||
|
||||
// the start index value of each tensor is
|
||||
// the sum of previous tensor's size. For example:
|
||||
// outs = [10, 0, 10, 10] ==> starts = [0, 10, 10, 20, 30]
|
||||
h_starts[0] = 0;
|
||||
for (int i = 0; i < xs_size; i++) {
|
||||
h_starts[i + 1] = h_starts[i] + outs[i]->numel();
|
||||
}
|
||||
auto* stable_h_starts = backends::gpu::RestoreHostMemIfCapturingCUDAGraph(
|
||||
h_starts, xs_size + 1);
|
||||
memory_utils::Copy(dev_ctx.GetPlace(),
|
||||
d_starts,
|
||||
cpu_place,
|
||||
stable_h_starts,
|
||||
(xs_size + 1) * sizeof(int64_t),
|
||||
dev_ctx.stream());
|
||||
|
||||
// copy each tensor of "outs" data address array to device
|
||||
auto h_out_addrs_mem = memory_utils::Alloc(cpu_place, xs_size * sizeof(T*));
|
||||
T** h_out_addrs = reinterpret_cast<T**>(h_out_addrs_mem->ptr());
|
||||
|
||||
auto d_out_addrs_mem = memory_utils::Alloc(
|
||||
dev_ctx.GetPlace(),
|
||||
xs_size * sizeof(T*),
|
||||
Stream(reinterpret_cast<StreamId>(dev_ctx.stream())));
|
||||
T** d_out_addrs = reinterpret_cast<T**>(d_out_addrs_mem->ptr());
|
||||
|
||||
for (size_t i = 0; i < xs_size; ++i) {
|
||||
h_out_addrs[i] = dev_ctx.Alloc<T>(outs[i]);
|
||||
}
|
||||
auto* stable_h_out_addrs =
|
||||
backends::gpu::RestoreHostMemIfCapturingCUDAGraph(h_out_addrs, xs_size);
|
||||
memory_utils::Copy(dev_ctx.GetPlace(),
|
||||
d_out_addrs,
|
||||
cpu_place,
|
||||
stable_h_out_addrs,
|
||||
xs_size * sizeof(T*),
|
||||
dev_ctx.stream());
|
||||
|
||||
// launch cuda kernel
|
||||
int64_t total_num = h_starts[xs_size];
|
||||
int64_t threads_per_block = std::min(static_cast<int64_t>(1024), total_num);
|
||||
int64_t elements_per_block =
|
||||
threads_per_block * 50; // each thread deal with 50 data
|
||||
int64_t blocks_per_grid =
|
||||
(total_num + elements_per_block - 1) / elements_per_block;
|
||||
FusedFillIf<T><<<blocks_per_grid,
|
||||
threads_per_block,
|
||||
(xs_size + 1) * sizeof(int64_t),
|
||||
dev_ctx.stream()>>>(
|
||||
d_out_addrs, xs_size, d_starts, static_cast<T>(0), found_inf_data);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, bool IsFoundInfOnCPU>
|
||||
class UpdateLossScalingFunctor<GPUContext, T, IsFoundInfOnCPU> {
|
||||
public:
|
||||
void operator()(const GPUContext& dev_ctx,
|
||||
const bool* found_inf_data,
|
||||
const T* pre_loss_scaling_data,
|
||||
const int* good_in_data,
|
||||
const int* bad_in_data,
|
||||
const int incr_every_n_steps,
|
||||
const int decr_every_n_nan_or_inf,
|
||||
const float incr_ratio,
|
||||
const float decr_ratio,
|
||||
T* updated_loss_scaling_data,
|
||||
int* good_out_data,
|
||||
int* bad_out_data) const {
|
||||
if (IsFoundInfOnCPU) {
|
||||
GpuUpdateLossScaling<T>
|
||||
<<<1, 1, 0, dev_ctx.stream()>>>(*found_inf_data,
|
||||
pre_loss_scaling_data,
|
||||
good_in_data,
|
||||
bad_in_data,
|
||||
incr_every_n_steps,
|
||||
decr_every_n_nan_or_inf,
|
||||
incr_ratio,
|
||||
decr_ratio,
|
||||
updated_loss_scaling_data,
|
||||
good_out_data,
|
||||
bad_out_data);
|
||||
} else {
|
||||
GpuUpdateLossScaling<T>
|
||||
<<<1, 1, 0, dev_ctx.stream()>>>(found_inf_data,
|
||||
pre_loss_scaling_data,
|
||||
good_in_data,
|
||||
bad_in_data,
|
||||
incr_every_n_steps,
|
||||
decr_every_n_nan_or_inf,
|
||||
incr_ratio,
|
||||
decr_ratio,
|
||||
updated_loss_scaling_data,
|
||||
good_out_data,
|
||||
bad_out_data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Kernels
|
||||
|
||||
template <typename T, typename Context>
|
||||
void CheckFiniteAndUnscaleKernel(const Context& dev_ctx,
|
||||
const std::vector<const DenseTensor*>& xs,
|
||||
const DenseTensor& scale,
|
||||
std::vector<DenseTensor*> outs,
|
||||
DenseTensor* found_infinite) {
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
|
||||
const MT* scale_data = scale.data<MT>();
|
||||
bool* found_inf_data = dev_ctx.template Alloc<bool>(found_infinite);
|
||||
|
||||
DenseTensor inverse_scale = Empty<MT>(dev_ctx, {1});
|
||||
MT* inverse_scale_v = inverse_scale.template data<MT>();
|
||||
|
||||
InverseAndMemset<MT><<<1, 1, 0, dev_ctx.stream()>>>(
|
||||
scale_data, inverse_scale_v, found_inf_data);
|
||||
|
||||
size_t xs_size = xs.size();
|
||||
if (xs_size == 0) return;
|
||||
|
||||
const auto& cpu_place = CPUPlace();
|
||||
// calculate each tensor's start index and copy to device
|
||||
auto h_starts_tensor =
|
||||
memory_utils::Alloc(cpu_place, (xs_size + 1) * sizeof(int64_t));
|
||||
int64_t* h_starts = reinterpret_cast<int64_t*>(h_starts_tensor->ptr());
|
||||
|
||||
auto d_starts_tensor =
|
||||
memory_utils::Alloc(dev_ctx.GetPlace(),
|
||||
(xs_size + 1) * sizeof(int64_t),
|
||||
Stream(reinterpret_cast<StreamId>(dev_ctx.stream())));
|
||||
int64_t* d_starts = reinterpret_cast<int64_t*>(d_starts_tensor->ptr());
|
||||
|
||||
// the start index value of each tensor is
|
||||
// the sum of previous tensor's size. For example:
|
||||
// x = [10, 0, 10, 10] ==> starts = [0, 10, 10, 20, 30]
|
||||
h_starts[0] = 0;
|
||||
for (int i = 1; i <= xs_size; i++) {
|
||||
h_starts[i] = h_starts[i - 1] + xs[i - 1]->numel();
|
||||
}
|
||||
int64_t total_num = h_starts[xs_size];
|
||||
auto* stable_h_starts =
|
||||
backends::gpu::RestoreHostMemIfCapturingCUDAGraph(h_starts, xs_size + 1);
|
||||
memory_utils::Copy(dev_ctx.GetPlace(),
|
||||
d_starts,
|
||||
cpu_place,
|
||||
stable_h_starts,
|
||||
(xs_size + 1) * sizeof(int64_t),
|
||||
dev_ctx.stream());
|
||||
|
||||
// copy each tensor's data address to device
|
||||
auto h_mem = memory_utils::Alloc(cpu_place, 2 * xs_size * sizeof(T*));
|
||||
const T** h_xs = reinterpret_cast<const T**>(h_mem->ptr());
|
||||
T** h_outs = reinterpret_cast<T**>(h_mem->ptr()) + xs_size;
|
||||
|
||||
auto d_mem =
|
||||
memory_utils::Alloc(dev_ctx.GetPlace(),
|
||||
2 * xs_size * sizeof(T*),
|
||||
Stream(reinterpret_cast<StreamId>(dev_ctx.stream())));
|
||||
const T** d_xs = reinterpret_cast<const T**>(d_mem->ptr());
|
||||
T** d_outs = reinterpret_cast<T**>(d_mem->ptr()) + xs_size;
|
||||
|
||||
for (size_t i = 0; i < xs_size; ++i) {
|
||||
h_xs[i] = xs[i]->data<T>();
|
||||
h_outs[i] = dev_ctx.template Alloc<T>(outs[i]);
|
||||
}
|
||||
auto* stable_h_xs =
|
||||
backends::gpu::RestoreHostMemIfCapturingCUDAGraph(h_xs, 2 * xs_size);
|
||||
memory_utils::Copy(dev_ctx.GetPlace(),
|
||||
d_xs,
|
||||
cpu_place,
|
||||
stable_h_xs,
|
||||
2 * xs_size * sizeof(T*),
|
||||
dev_ctx.stream());
|
||||
|
||||
// Launch Kernel
|
||||
int threads_per_block = std::min(static_cast<int64_t>(1024), total_num);
|
||||
int elements_per_block =
|
||||
threads_per_block * 20; // each thread deal with 20 number
|
||||
int blocks_per_grid =
|
||||
(total_num + elements_per_block - 1) / elements_per_block;
|
||||
CheckFiniteAndUnscale<T, MT><<<blocks_per_grid,
|
||||
threads_per_block,
|
||||
(xs_size + 1) * sizeof(int64_t),
|
||||
dev_ctx.stream()>>>(
|
||||
d_xs, inverse_scale_v, xs_size, d_starts, found_inf_data, d_outs);
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(check_finite_and_unscale,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CheckFiniteAndUnscaleKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {
|
||||
kernel->OutputAt(1).SetDataType(phi::DataType::BOOL);
|
||||
}
|
||||
|
||||
PD_REGISTER_KERNEL(update_loss_scaling,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::UpdateLossScalingKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {
|
||||
kernel->InputAt(1).SetBackend(phi::Backend::ALL_BACKEND);
|
||||
if (kernel_key.dtype() == phi::DataType::FLOAT16 ||
|
||||
kernel_key.dtype() == phi::DataType::BFLOAT16) {
|
||||
kernel->OutputAt(1).SetDataType(phi::DataType::FLOAT32);
|
||||
}
|
||||
kernel->OutputAt(2).SetDataType(phi::DataType::INT32);
|
||||
kernel->OutputAt(3).SetDataType(phi::DataType::INT32);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/angle_grad_kernel.h"
|
||||
#include "paddle/phi/kernels/impl/angle_grad_kernel_impl.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
PD_REGISTER_KERNEL(angle_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AngleGradKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {
|
||||
kernel->InputAt(1).SetDataType(phi::dtype::ToReal(kernel_key.dtype()));
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/angle_kernel.h"
|
||||
#include "paddle/phi/kernels/impl/angle_kernel_impl.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
PD_REGISTER_KERNEL(angle,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AngleKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {
|
||||
kernel->OutputAt(0).SetDataType(phi::DataType::UNDEFINED);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2025 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/gpu/ap_facade_kernel.h"
|
||||
#include "paddle/common/enforce.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ApFacadeKernel(const Context& dev_ctx,
|
||||
const optional<std::vector<const DenseTensor*>>& xs,
|
||||
int64_t num_outputs,
|
||||
const std::string& custom_op_name,
|
||||
const std::string& infer_meta_func_name,
|
||||
const std::string& infer_symbolic_func_name,
|
||||
const std::string& serialized_attributes,
|
||||
std::vector<DenseTensor*> outs) {
|
||||
PADDLE_THROW(
|
||||
common::errors::Unimplemented("ap_facade has no kernel registered."));
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(ap_facade,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ApFacadeKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
phi::bfloat16,
|
||||
phi::float16,
|
||||
int64_t,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ApFacadeKernel(const Context& dev_ctx,
|
||||
const optional<std::vector<const DenseTensor*>>& xs,
|
||||
int64_t num_outputs,
|
||||
const std::string& custom_op_name,
|
||||
const std::string& infer_meta_func_name,
|
||||
const std::string& infer_symbolic_func_name,
|
||||
const std::string& serialized_attributes,
|
||||
std::vector<DenseTensor*> outs);
|
||||
|
||||
} // namespace phi
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2025 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/gpu/ap_trivial_fusion_begin_kernel.h"
|
||||
#include "paddle/common/enforce.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ApTrivialFusionBeginKernel(
|
||||
const Context& dev_ctx,
|
||||
const optional<std::vector<const DenseTensor*>>& xs,
|
||||
DenseTensor* out) {
|
||||
PADDLE_THROW(common::errors::Unimplemented(
|
||||
"pd_op.ap_trivial_fusion_begin has no kernel registered."));
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(ap_trivial_fusion_begin,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ApTrivialFusionBeginKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
phi::bfloat16,
|
||||
phi::float16,
|
||||
int64_t,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ApTrivialFusionBeginKernel(
|
||||
const Context& dev_ctx,
|
||||
const optional<std::vector<const DenseTensor*>>& xs,
|
||||
DenseTensor* out);
|
||||
|
||||
} // namespace phi
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2025 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/gpu/ap_trivial_fusion_end_kernel.h"
|
||||
#include "paddle/common/enforce.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ApTrivialFusionEndKernel(
|
||||
const Context& dev_ctx,
|
||||
const optional<std::vector<const DenseTensor*>>& xs,
|
||||
DenseTensor* out) {
|
||||
PADDLE_THROW(common::errors::Unimplemented(
|
||||
"pd_op.ap_trivial_fusion_end has no kernel registered."));
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(ap_trivial_fusion_end,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ApTrivialFusionEndKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
phi::bfloat16,
|
||||
phi::float16,
|
||||
int64_t,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ApTrivialFusionEndKernel(
|
||||
const Context& dev_ctx,
|
||||
const optional<std::vector<const DenseTensor*>>& xs,
|
||||
DenseTensor* out);
|
||||
|
||||
} // namespace phi
|
||||
@@ -0,0 +1,126 @@
|
||||
// Copyright (c) 2025 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/gpu/ap_variadic_kernel.h"
|
||||
#include "paddle/ap/include/axpr/data_type_util.h"
|
||||
#include "paddle/ap/include/kernel_dispatch/ap_variadic_kernel.h"
|
||||
#include "paddle/ap/include/paddle/phi/device_ctx.h"
|
||||
#include "paddle/common/enforce.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename Context>
|
||||
void AllocateOutTensors(const Context& dev_ctx,
|
||||
const std::vector<DenseTensor*>& outs) {
|
||||
for (auto* out : outs) {
|
||||
auto out_dtype = ap::axpr::GetDataTypeFromPhiDataType(out->dtype());
|
||||
PADDLE_ENFORCE_EQ(out_dtype.HasOkValue(),
|
||||
true,
|
||||
common::errors::InvalidArgument(
|
||||
"GetDataTypeFromPhiDataType() failed !"));
|
||||
|
||||
out_dtype.GetOkValue().Match(
|
||||
[&](const ap::axpr::CppDataType<ap::adt::Undefined>&) {
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"allocate not support undefined !"));
|
||||
},
|
||||
[&](const ap::axpr::CppDataType<uint64_t>&) {
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"allocate not support uint64_t !"));
|
||||
},
|
||||
[&](const ap::axpr::CppDataType<uint32_t>&) {
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"allocate not support uint32_t !"));
|
||||
},
|
||||
[&](const ap::axpr::CppDataType<uint16_t>&) {
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"allocate not support uint16_t !"));
|
||||
},
|
||||
[&](const auto& impl) {
|
||||
using tensor_type = typename std::decay_t<decltype(impl)>::type;
|
||||
dev_ctx.template Alloc<tensor_type>(out);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ApVariadicKernel(const Context& dev_ctx,
|
||||
const std::vector<const DenseTensor*>& xs,
|
||||
int num_outputs,
|
||||
const std::string& code_module_lambda,
|
||||
const std::string& infer_symbolic_lambda,
|
||||
const std::string& infer_meta_lambda,
|
||||
const std::string& kernel_dispatch_lambda,
|
||||
const std::string& kernel_dispatch_const_data_lambda,
|
||||
std::vector<DenseTensor*> outs) {
|
||||
PADDLE_ENFORCE_GT(
|
||||
xs.size(),
|
||||
0,
|
||||
common::errors::InvalidArgument(
|
||||
"At least 1 input is required. current number out uts: // %d",
|
||||
xs.size()));
|
||||
PADDLE_ENFORCE_GT(
|
||||
outs.size(),
|
||||
0,
|
||||
common::errors::InvalidArgument(
|
||||
"num_outputs must be greater than 1. current _outputs: // %d",
|
||||
outs.size()));
|
||||
|
||||
AllocateOutTensors<Context>(dev_ctx, outs);
|
||||
std::shared_ptr<ap::kernel_dispatch::DeviceCtxImpl> impl =
|
||||
std::make_shared<ap::paddle::DeviceCtx<Context>>(&dev_ctx);
|
||||
ap::kernel_dispatch::DeviceCtx ap_device_ctx{impl};
|
||||
const auto& ret =
|
||||
ap::kernel_dispatch::ApVariadicKernel(ap_device_ctx,
|
||||
xs,
|
||||
num_outputs,
|
||||
code_module_lambda,
|
||||
infer_meta_lambda,
|
||||
kernel_dispatch_lambda,
|
||||
kernel_dispatch_const_data_lambda,
|
||||
outs);
|
||||
PADDLE_ENFORCE_EQ(
|
||||
ret.HasError(),
|
||||
false,
|
||||
common::errors::Fatal("ap_variadic failed. \nTraceback (most "
|
||||
"recent call last):\n%s\n%s: %s. ",
|
||||
ret.GetError().CallStackToString(),
|
||||
ret.GetError().class_name(),
|
||||
ret.GetError().msg()));
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
PD_REGISTER_KERNEL(ap_variadic,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ApVariadicKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16) {}
|
||||
#else
|
||||
PD_REGISTER_KERNEL(ap_variadic,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ApVariadicKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ApVariadicKernel(const Context& dev_ctx,
|
||||
const std::vector<const DenseTensor*>& xs,
|
||||
int num_outputs,
|
||||
const std::string& code_module_lambda,
|
||||
const std::string& infer_symbolic_lambda,
|
||||
const std::string& infer_meta_lambda,
|
||||
const std::string& kernel_dispatch_lambda,
|
||||
const std::string& kernel_dispatch_const_data_lambda,
|
||||
std::vector<DenseTensor*> outs);
|
||||
|
||||
} // namespace phi
|
||||
@@ -0,0 +1,208 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
* Copyright (c) 2022-2023, NVIDIA CORPORATION. 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/apply_per_channel_scale_kernel.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <cmath>
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/common/datatype_traits.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
namespace {
|
||||
#ifdef PADDLE_WITH_CUDA
|
||||
template <typename T>
|
||||
struct CUDA_HALF_2_TYPE_TARIS {};
|
||||
|
||||
template <>
|
||||
struct CUDA_HALF_2_TYPE_TARIS<half> {
|
||||
using type = half2;
|
||||
};
|
||||
|
||||
#ifdef PADDLE_CUDA_BF16
|
||||
template <>
|
||||
struct CUDA_HALF_2_TYPE_TARIS<__nv_bfloat16> {
|
||||
using type = __nv_bfloat162;
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
struct HalfMul2 {};
|
||||
|
||||
template <>
|
||||
struct HalfMul2<half2> {
|
||||
static __device__ __forceinline__ half2 apply(const half2& x,
|
||||
const half2& y) {
|
||||
return __hmul2(x, y);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef PADDLE_CUDA_BF16
|
||||
template <>
|
||||
struct HalfMul2<__nv_bfloat162> {
|
||||
static __device__ __forceinline__ __nv_bfloat162
|
||||
apply(const __nv_bfloat162& x, const __nv_bfloat162& y) {
|
||||
#if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 800))
|
||||
return __hmul2(x, y);
|
||||
#else
|
||||
float fxl, fxh, fyl, fyh;
|
||||
fxl = __low2float(x);
|
||||
fxh = __high2float(x);
|
||||
fyl = __low2float(y);
|
||||
fyh = __high2float(y);
|
||||
return __floats2bfloat162_rn(fxl * fyl, fxh * fyh);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename T, int kProcessRows, typename AccessType>
|
||||
__global__ void apply_per_channel_scale(
|
||||
const T* act, const T* scales, int rows, int cols, T* out) {
|
||||
using HALF_2_TYPE = typename CUDA_HALF_2_TYPE_TARIS<T>::type;
|
||||
static constexpr int kElems = sizeof(AccessType) / sizeof(T);
|
||||
T scale[kElems], act_vec[kElems];
|
||||
int64_t col_offset =
|
||||
static_cast<int64_t>(blockIdx.x) * static_cast<int64_t>(blockDim.x) +
|
||||
static_cast<int64_t>(threadIdx.x);
|
||||
int row_offset = blockIdx.y;
|
||||
if (col_offset * kElems >= cols || row_offset * kProcessRows >= rows) return;
|
||||
act += row_offset * kProcessRows * cols;
|
||||
out += row_offset * kProcessRows * cols;
|
||||
*reinterpret_cast<AccessType*>(scale) =
|
||||
reinterpret_cast<const AccessType*>(scales)[col_offset];
|
||||
#pragma unroll
|
||||
for (int i = 0; i < kProcessRows; ++i) {
|
||||
*reinterpret_cast<AccessType*>(act_vec) =
|
||||
reinterpret_cast<const AccessType*>(act + i * cols)[col_offset];
|
||||
if constexpr (kElems % 2 == 0 && (std::is_same<T, half>::value
|
||||
#ifdef PADDLE_CUDA_BF16
|
||||
|| std::is_same<T, __nv_bfloat16>::value
|
||||
#endif
|
||||
)) {
|
||||
#pragma unroll
|
||||
for (int j = 0; j < kElems; j += 2) {
|
||||
*reinterpret_cast<HALF_2_TYPE*>(act_vec + j) =
|
||||
HalfMul2<HALF_2_TYPE>::apply(
|
||||
*reinterpret_cast<HALF_2_TYPE*>(act_vec + j),
|
||||
*reinterpret_cast<HALF_2_TYPE*>(scale + j));
|
||||
}
|
||||
} else {
|
||||
#pragma unroll
|
||||
for (int j = 0; j < kElems; ++j) {
|
||||
act_vec[j] *= scale[j];
|
||||
}
|
||||
}
|
||||
reinterpret_cast<AccessType*>(out + i * cols)[col_offset] =
|
||||
*reinterpret_cast<AccessType*>(act_vec);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, int kProcessRows, typename AccessType = float4>
|
||||
void apply_per_channel_scale_launcher(const T* act,
|
||||
const T* scales,
|
||||
int rows,
|
||||
int cols,
|
||||
T* out,
|
||||
cudaStream_t stream = 0) {
|
||||
static constexpr int kElems = sizeof(AccessType) / sizeof(T);
|
||||
dim3 block(128);
|
||||
dim3 grid((cols / kElems + block.x - 1) / block.x,
|
||||
(rows + kProcessRows - 1) / kProcessRows);
|
||||
apply_per_channel_scale<T, kProcessRows, AccessType>
|
||||
<<<grid, block, 0, stream>>>(act, scales, rows, cols, out);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ApplyPerChannelScaleKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const DenseTensor& scales,
|
||||
DenseTensor* out) {
|
||||
#ifdef PADDLE_WITH_CUDA
|
||||
using DataType = typename PDDataTypeTraits<T>::DataType;
|
||||
int64_t rows = x.dims()[0];
|
||||
int64_t cols = x.dims()[1];
|
||||
int64_t elems = rows * cols;
|
||||
const T* x_data = x.data<T>();
|
||||
const T* scales_data = scales.data<T>();
|
||||
T* out_data = dev_ctx.template Alloc<T>(out);
|
||||
if (elems < 2048 * 2048) {
|
||||
apply_per_channel_scale_launcher<DataType, 1, float4>(
|
||||
reinterpret_cast<const DataType*>(x_data),
|
||||
reinterpret_cast<const DataType*>(scales_data),
|
||||
rows,
|
||||
cols,
|
||||
reinterpret_cast<DataType*>(out_data),
|
||||
dev_ctx.stream());
|
||||
} else if (elems < 4096 * 4096) {
|
||||
apply_per_channel_scale_launcher<DataType, 4, float4>(
|
||||
reinterpret_cast<const DataType*>(x_data),
|
||||
reinterpret_cast<const DataType*>(scales_data),
|
||||
rows,
|
||||
cols,
|
||||
reinterpret_cast<DataType*>(out_data),
|
||||
dev_ctx.stream());
|
||||
} else if (elems < 8192 * 8192) {
|
||||
apply_per_channel_scale_launcher<DataType, 8, float4>(
|
||||
reinterpret_cast<const DataType*>(x_data),
|
||||
reinterpret_cast<const DataType*>(scales_data),
|
||||
rows,
|
||||
cols,
|
||||
reinterpret_cast<DataType*>(out_data),
|
||||
dev_ctx.stream());
|
||||
} else {
|
||||
PADDLE_ENFORCE_LE_INT_MAX(rows, "rows");
|
||||
PADDLE_ENFORCE_LE_INT_MAX(cols, "cols");
|
||||
apply_per_channel_scale_launcher<DataType, 16, float4>(
|
||||
reinterpret_cast<const DataType*>(x_data),
|
||||
reinterpret_cast<const DataType*>(scales_data),
|
||||
rows,
|
||||
cols,
|
||||
reinterpret_cast<DataType*>(out_data),
|
||||
dev_ctx.stream());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(apply_per_channel_scale,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ApplyPerChannelScaleKernel,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,171 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/arange_kernel.h"
|
||||
|
||||
#include "paddle/common/errors.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/core/enforce.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/core/tensor_utils.h"
|
||||
#include "paddle/phi/core/visit_type.h"
|
||||
#include "paddle/phi/kernels/funcs/range_function.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename OUT_TYPE>
|
||||
__global__ void Range(T start, T step, int64_t size, OUT_TYPE* out) {
|
||||
CUDA_KERNEL_LOOP_TYPE(index, size, int64_t) {
|
||||
out[index] = static_cast<OUT_TYPE>(start + step * index);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ArangeTensorKernel(const Context& dev_ctx,
|
||||
const DenseTensor& start,
|
||||
const DenseTensor& end,
|
||||
const DenseTensor& step,
|
||||
DenseTensor* out) {
|
||||
bool any_float = phi::IsFloatingType(start.dtype()) ||
|
||||
phi::IsFloatingType(end.dtype()) ||
|
||||
phi::IsFloatingType(step.dtype());
|
||||
int64_t size = 0;
|
||||
using MPType = typename phi::dtype::MPTypeTrait<T>::Type;
|
||||
Scalar start_scalar(start);
|
||||
Scalar end_scalar(end);
|
||||
Scalar step_scalar(step);
|
||||
if (any_float) {
|
||||
double sv = start_scalar.to<double>();
|
||||
double ev = end_scalar.to<double>();
|
||||
double stv = step_scalar.to<double>();
|
||||
funcs::GetSize<double>(sv, ev, stv, &size);
|
||||
} else {
|
||||
int64_t sv = start_scalar.to<int64_t>();
|
||||
int64_t ev = end_scalar.to<int64_t>();
|
||||
int64_t stv = step_scalar.to<int64_t>();
|
||||
funcs::GetSize<int64_t>(sv, ev, stv, &size);
|
||||
}
|
||||
MPType start_value = start_scalar.to<MPType>();
|
||||
MPType step_value = step_scalar.to<MPType>();
|
||||
|
||||
out->Resize({size});
|
||||
T* out_data = dev_ctx.template Alloc<T>(out);
|
||||
|
||||
auto stream = dev_ctx.stream();
|
||||
int64_t block = std::min(size, static_cast<int64_t>(256));
|
||||
if (block == 0) {
|
||||
return;
|
||||
}
|
||||
int64_t grid = (size + block - 1) / block;
|
||||
Range<MPType, T>
|
||||
<<<grid, block, 0, stream>>>(start_value, step_value, size, out_data);
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ArangeNullaryKernel(const Context& dev_ctx,
|
||||
const T start_value,
|
||||
const T end_value,
|
||||
const T step_value,
|
||||
DenseTensor* out) {
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
MT start_value_mpt = static_cast<MT>(start_value);
|
||||
MT end_value_mpt = static_cast<MT>(end_value);
|
||||
MT step_value_mpt = static_cast<MT>(step_value);
|
||||
int64_t size = 0;
|
||||
funcs::GetSize(start_value_mpt, end_value_mpt, step_value_mpt, &size);
|
||||
out->Resize({size});
|
||||
T* out_data = dev_ctx.template Alloc<T>(out);
|
||||
|
||||
auto stream = dev_ctx.stream();
|
||||
int64_t block = std::min(size, static_cast<int64_t>(256));
|
||||
if (block == 0) {
|
||||
return;
|
||||
}
|
||||
int64_t grid = (size + block - 1) / block;
|
||||
Range<MT, T><<<grid, block, 0, stream>>>(
|
||||
start_value_mpt, step_value_mpt, size, out_data);
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ArangeKernel(const Context& dev_ctx,
|
||||
const Scalar& start,
|
||||
const Scalar& end,
|
||||
const Scalar& step,
|
||||
DenseTensor* out) {
|
||||
bool is_floating = phi::IsFloatingType(start.dtype()) ||
|
||||
phi::IsFloatingType(end.dtype()) ||
|
||||
phi::IsFloatingType(step.dtype());
|
||||
using MPType = typename phi::dtype::MPTypeTrait<T>::Type;
|
||||
int64_t size = 0;
|
||||
if (is_floating) {
|
||||
double sv = start.to<double>();
|
||||
double ev = end.to<double>();
|
||||
double stv = step.to<double>();
|
||||
funcs::GetSize<double>(sv, ev, stv, &size);
|
||||
} else {
|
||||
int64_t sv = start.to<int64_t>();
|
||||
int64_t ev = end.to<int64_t>();
|
||||
int64_t stv = step.to<int64_t>();
|
||||
funcs::GetSize<int64_t>(sv, ev, stv, &size);
|
||||
}
|
||||
MPType start_value = start.to<MPType>();
|
||||
MPType step_value = step.to<MPType>();
|
||||
out->Resize({size});
|
||||
T* out_data = dev_ctx.template Alloc<T>(out);
|
||||
|
||||
auto stream = dev_ctx.stream();
|
||||
int64_t block = std::min(size, static_cast<int64_t>(256));
|
||||
if (block == 0) {
|
||||
return;
|
||||
}
|
||||
int64_t grid = (size + block - 1) / block;
|
||||
Range<MPType, T>
|
||||
<<<grid, block, 0, stream>>>(start_value, step_value, size, out_data);
|
||||
}
|
||||
|
||||
template void ArangeNullaryKernel<int64_t, GPUContext>(const GPUContext&,
|
||||
const int64_t,
|
||||
const int64_t,
|
||||
const int64_t,
|
||||
DenseTensor*);
|
||||
template void ArangeNullaryKernel<int, GPUContext>(
|
||||
const GPUContext&, const int, const int, const int, DenseTensor*);
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(arange_tensor,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ArangeTensorKernel,
|
||||
float,
|
||||
double,
|
||||
int64_t,
|
||||
int,
|
||||
phi::float16,
|
||||
phi::bfloat16) {
|
||||
kernel->InputAt(0).SetBackend(phi::Backend::ALL_BACKEND);
|
||||
kernel->InputAt(1).SetBackend(phi::Backend::ALL_BACKEND);
|
||||
kernel->InputAt(2).SetBackend(phi::Backend::ALL_BACKEND);
|
||||
}
|
||||
|
||||
PD_REGISTER_KERNEL(arange,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ArangeKernel,
|
||||
float,
|
||||
double,
|
||||
int64_t,
|
||||
int,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,297 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/arg_min_max_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
#if defined(__NVCC__) || defined(__HIPCC__)
|
||||
|
||||
#include <limits>
|
||||
#include "paddle/common/ddim.h"
|
||||
#include "paddle/phi/core/utils/data_type.h"
|
||||
#include "paddle/phi/kernels/funcs/cub.h"
|
||||
#include "paddle/phi/kernels/funcs/math_function.h"
|
||||
namespace phi {
|
||||
|
||||
namespace { // NOLINT
|
||||
template <typename K, typename V>
|
||||
using KeyValuePair = cub::KeyValuePair<K, V>;
|
||||
|
||||
} // namespace
|
||||
|
||||
#define FIXED_BLOCK_DIM_CASE_BASE(log2_block_dim, ...) \
|
||||
case (1 << (log2_block_dim)): { \
|
||||
constexpr auto kBlockDim = (1 << (log2_block_dim)); \
|
||||
__VA_ARGS__; \
|
||||
} break
|
||||
|
||||
#define FIXED_BLOCK_DIM_CASE(...) \
|
||||
FIXED_BLOCK_DIM_CASE_BASE(10, ##__VA_ARGS__); \
|
||||
FIXED_BLOCK_DIM_CASE_BASE(9, ##__VA_ARGS__); \
|
||||
FIXED_BLOCK_DIM_CASE_BASE(8, ##__VA_ARGS__); \
|
||||
FIXED_BLOCK_DIM_CASE_BASE(7, ##__VA_ARGS__); \
|
||||
FIXED_BLOCK_DIM_CASE_BASE(6, ##__VA_ARGS__); \
|
||||
FIXED_BLOCK_DIM_CASE_BASE(5, ##__VA_ARGS__); \
|
||||
FIXED_BLOCK_DIM_CASE_BASE(4, ##__VA_ARGS__); \
|
||||
FIXED_BLOCK_DIM_CASE_BASE(3, ##__VA_ARGS__);
|
||||
|
||||
template <typename T,
|
||||
typename IndType,
|
||||
class Reducer,
|
||||
size_t BlockDim,
|
||||
typename IndexType>
|
||||
__global__ void ArgCUDAKernel(const int64_t height, // n * h
|
||||
const int64_t width, // c
|
||||
const int64_t post_size, // h
|
||||
const Reducer reducer,
|
||||
const T init,
|
||||
const T* in,
|
||||
IndType* out) {
|
||||
typedef cub::BlockReduce<KeyValuePair<IndexType, T>, BlockDim> BlockReduce;
|
||||
__shared__ typename BlockReduce::TempStorage temp_storage;
|
||||
|
||||
for (IndexType idx = blockIdx.x; idx < height; idx += gridDim.x) {
|
||||
KeyValuePair<IndexType, T> kv_pair = {-1, init};
|
||||
IndexType h = idx / post_size;
|
||||
IndexType w = idx % post_size;
|
||||
for (IndexType k = threadIdx.x; k < width; k += blockDim.x) {
|
||||
kv_pair =
|
||||
reducer({k, in[h * width * post_size + k * post_size + w]}, kv_pair);
|
||||
}
|
||||
kv_pair = BlockReduce(temp_storage).Reduce(kv_pair, reducer);
|
||||
if (threadIdx.x == 0) {
|
||||
out[idx] = static_cast<IndType>(kv_pair.key);
|
||||
}
|
||||
__syncthreads();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename IndType, class Reducer, typename IndexType>
|
||||
void ComputeFullArg(const GPUContext& dev_ctx,
|
||||
const DenseTensor& input,
|
||||
DenseTensor* indices,
|
||||
const int64_t pre,
|
||||
const int64_t post,
|
||||
const int64_t n) {
|
||||
auto cu_stream = dev_ctx.stream();
|
||||
auto ComputeBlockSize = [](int64_t col) {
|
||||
auto block_size = 8;
|
||||
if (col > 512)
|
||||
block_size = 1024;
|
||||
else if (col > 256)
|
||||
block_size = 512;
|
||||
else if (col > 128)
|
||||
block_size = 256;
|
||||
else if (col > 64)
|
||||
block_size = 128;
|
||||
else if (col > 32)
|
||||
block_size = 64;
|
||||
else if (col > 16)
|
||||
block_size = 32;
|
||||
else if (col > 8)
|
||||
block_size = 16;
|
||||
return block_size;
|
||||
};
|
||||
|
||||
int64_t max_grid_dimx = dev_ctx.GetCUDAMaxGridDimSize()[0];
|
||||
int64_t height = pre * post;
|
||||
int64_t width = n;
|
||||
int64_t grid_size = height < max_grid_dimx ? height : max_grid_dimx;
|
||||
|
||||
const T* in_data = input.data<T>();
|
||||
IndType* out_data = dev_ctx.template Alloc<IndType>(indices);
|
||||
|
||||
if (typeid(Reducer) == typeid(cub::ArgMax)) {
|
||||
switch (ComputeBlockSize(width)) {
|
||||
FIXED_BLOCK_DIM_CASE(
|
||||
ArgCUDAKernel<T, IndType, Reducer, kBlockDim, IndexType>
|
||||
<<<grid_size, kBlockDim, 0, cu_stream>>>(
|
||||
height,
|
||||
width,
|
||||
post,
|
||||
Reducer(),
|
||||
std::numeric_limits<T>::lowest(),
|
||||
in_data,
|
||||
out_data));
|
||||
}
|
||||
} else {
|
||||
switch (ComputeBlockSize(width)) {
|
||||
FIXED_BLOCK_DIM_CASE(
|
||||
ArgCUDAKernel<T, IndType, Reducer, kBlockDim, IndexType>
|
||||
<<<grid_size, kBlockDim, 0, cu_stream>>>(
|
||||
height,
|
||||
width,
|
||||
post,
|
||||
Reducer(),
|
||||
std::numeric_limits<T>::max(),
|
||||
in_data,
|
||||
out_data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Context, typename T, class Reducer>
|
||||
struct VisitDataCudaArgMinMaxFunctor {
|
||||
const Context& dev_ctx;
|
||||
const DenseTensor& x;
|
||||
int64_t axis;
|
||||
bool keepdims;
|
||||
bool flatten;
|
||||
DenseTensor* out;
|
||||
|
||||
explicit VisitDataCudaArgMinMaxFunctor(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
int64_t axis,
|
||||
bool keepdims,
|
||||
bool flatten,
|
||||
DenseTensor* out)
|
||||
: dev_ctx(dev_ctx),
|
||||
x(x),
|
||||
axis(axis),
|
||||
keepdims(keepdims),
|
||||
flatten(flatten),
|
||||
out(out) {}
|
||||
|
||||
template <typename IndType>
|
||||
void apply() const {
|
||||
DDim x_dims;
|
||||
int new_axis = axis;
|
||||
if (flatten) {
|
||||
x_dims = make_ddim({x.numel()});
|
||||
// if flatten, the axis just as 0
|
||||
new_axis = 0;
|
||||
} else {
|
||||
x_dims = x.dims();
|
||||
if (axis < 0) new_axis = axis + x.dims().size();
|
||||
}
|
||||
if (x.numel() == 0) {
|
||||
dev_ctx.template Alloc<IndType>(out);
|
||||
return;
|
||||
}
|
||||
// For 0D Tensor
|
||||
if (x.dims().size() == 0) {
|
||||
dev_ctx.template Alloc<IndType>(out);
|
||||
funcs::set_constant(dev_ctx, out, static_cast<IndType>(0));
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t numel = x.numel();
|
||||
int64_t groups = numel / x_dims[new_axis];
|
||||
int64_t pre = 1;
|
||||
int64_t post = 1;
|
||||
int64_t n = x_dims[new_axis];
|
||||
|
||||
for (int i = 0; i < new_axis; i++) {
|
||||
pre *= x_dims[i];
|
||||
}
|
||||
|
||||
for (int i = new_axis + 1; i < x_dims.size(); i++) {
|
||||
post *= x_dims[i];
|
||||
}
|
||||
|
||||
if (numel > std::numeric_limits<int32_t>::max()) {
|
||||
ComputeFullArg<T, IndType, Reducer, int64_t>(
|
||||
dev_ctx, x, out, pre, post, n);
|
||||
} else {
|
||||
ComputeFullArg<T, IndType, Reducer, int32_t>(
|
||||
dev_ctx, x, out, pre, post, n);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Context, typename T, class Reducer>
|
||||
void ArgMinMaxOpCUDAKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const Scalar& axis,
|
||||
bool keepdims,
|
||||
bool flatten,
|
||||
DataType dtype,
|
||||
DenseTensor* out) {
|
||||
PADDLE_ENFORCE_GE(
|
||||
x.numel(),
|
||||
0,
|
||||
common::errors::InvalidArgument(
|
||||
"argmin/argmax input numel must > 0, bug got %d", x.numel()));
|
||||
if (dtype == DataType::UNDEFINED) {
|
||||
phi::VisitDataTypeTiny(
|
||||
DataType::INT64,
|
||||
VisitDataCudaArgMinMaxFunctor<Context, T, Reducer>(
|
||||
dev_ctx, x, axis.to<int64_t>(), keepdims, flatten, out));
|
||||
return;
|
||||
}
|
||||
VisitDataTypeTiny(
|
||||
dtype,
|
||||
VisitDataCudaArgMinMaxFunctor<Context, T, Reducer>(
|
||||
dev_ctx, x, axis.to<int64_t>(), keepdims, flatten, out));
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ArgMinKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const Scalar& axis,
|
||||
bool keepdims,
|
||||
bool flatten,
|
||||
DataType dtype,
|
||||
DenseTensor* out) {
|
||||
ArgMinMaxOpCUDAKernel<Context, T, cub::ArgMin>(
|
||||
dev_ctx, x, axis, keepdims, flatten, dtype, out);
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ArgMaxKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const Scalar& axis,
|
||||
bool keepdims,
|
||||
bool flatten,
|
||||
DataType dtype,
|
||||
DenseTensor* out) {
|
||||
ArgMinMaxOpCUDAKernel<Context, T, cub::ArgMax>(
|
||||
dev_ctx, x, axis, keepdims, flatten, dtype, out);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(argmin,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ArgMinKernel,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
float,
|
||||
double,
|
||||
int32_t,
|
||||
int64_t,
|
||||
int16_t,
|
||||
uint8_t) {
|
||||
kernel->OutputAt(0).SetDataType(phi::DataType::UNDEFINED);
|
||||
}
|
||||
|
||||
PD_REGISTER_KERNEL(argmax,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ArgMaxKernel,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
float,
|
||||
double,
|
||||
int32_t,
|
||||
int64_t,
|
||||
int16_t,
|
||||
uint8_t) {
|
||||
kernel->OutputAt(0).SetDataType(phi::DataType::UNDEFINED);
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
// 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 <thrust/copy.h>
|
||||
#include <thrust/execution_policy.h>
|
||||
#include <thrust/sequence.h>
|
||||
#include <thrust/sort.h>
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/argsort_kernel.h"
|
||||
#include "paddle/phi/kernels/funcs/cub.h"
|
||||
#include "paddle/phi/kernels/funcs/math_function.h"
|
||||
#include "paddle/phi/kernels/primitive/functor_primitives.h"
|
||||
#include "paddle/phi/kernels/transpose_kernel.h"
|
||||
|
||||
#ifdef __HIPCC__
|
||||
#include <rocprim/config.hpp>
|
||||
#if defined(ROCPRIM_VERSION) && ROCPRIM_VERSION >= 400000
|
||||
// rocPRIM 4.x (ROCm 7.0+) removed rocprim::detail::radix_key_codec_base.
|
||||
// This TU has no actual cub::*/thrust::*/rocprim::* sort calls, so no
|
||||
// replacement traits are needed; keep this arm empty.
|
||||
#else
|
||||
namespace rocprim {
|
||||
namespace detail {
|
||||
template <>
|
||||
struct radix_key_codec_base<phi::float16>
|
||||
: radix_key_codec_integral<phi::float16, uint16_t> {};
|
||||
|
||||
template <>
|
||||
struct radix_key_codec_base<phi::bfloat16>
|
||||
: radix_key_codec_integral<phi::bfloat16, uint16_t> {};
|
||||
} // namespace detail
|
||||
} // namespace rocprim
|
||||
#endif // ROCPRIM_VERSION
|
||||
#else
|
||||
// set cub base traits in order to handle float16
|
||||
namespace cub {
|
||||
template <>
|
||||
struct NumericTraits<phi::float16>
|
||||
: BaseTraits<FLOATING_POINT, true, false, uint16_t, phi::float16> {};
|
||||
|
||||
template <>
|
||||
struct NumericTraits<phi::bfloat16>
|
||||
: BaseTraits<FLOATING_POINT, true, false, uint16_t, phi::bfloat16> {};
|
||||
} // namespace cub
|
||||
#endif
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename IndType>
|
||||
static __global__ void FillFlattenGrad(const T* dO,
|
||||
const IndType* indices,
|
||||
int64_t size,
|
||||
T* dX) {
|
||||
int64_t index =
|
||||
static_cast<int64_t>(threadIdx.x) +
|
||||
static_cast<int64_t>(blockIdx.x) * static_cast<int64_t>(blockDim.x);
|
||||
int stride = blockDim.x * gridDim.x;
|
||||
for (int64_t i = index; i < size; i += stride) {
|
||||
dX[indices[i]] = dO[i];
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename IndType>
|
||||
static __global__ void FillGrad(const T* dO,
|
||||
const IndType* indices,
|
||||
T* dX,
|
||||
IndType num_rows,
|
||||
IndType num_cols) {
|
||||
int col_id = threadIdx.x;
|
||||
int row_id = blockIdx.x;
|
||||
|
||||
for (IndType j = row_id; j < num_rows; j += gridDim.x) {
|
||||
for (IndType i = col_id; i < num_cols; i += blockDim.x) {
|
||||
dX[j * num_cols + indices[j * num_cols + i]] = dO[j * num_cols + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename IndType>
|
||||
void ArgFullAssign(const GPUContext& dev_ctx,
|
||||
const DenseTensor* dO,
|
||||
const DenseTensor* indices,
|
||||
DenseTensor* dX,
|
||||
const IndType num_rows,
|
||||
const IndType num_cols) {
|
||||
auto cu_stream = dev_ctx.stream();
|
||||
|
||||
auto ComputeBlockSize = [](IndType col) {
|
||||
if (col > 512)
|
||||
return 1024;
|
||||
else if (col > 256 && col <= 512)
|
||||
return 512;
|
||||
else if (col > 128 && col <= 256)
|
||||
return 256;
|
||||
else if (col > 64 && col <= 128)
|
||||
return 128;
|
||||
else
|
||||
return 64;
|
||||
};
|
||||
|
||||
int block_size = ComputeBlockSize(num_cols);
|
||||
|
||||
int maxGridDimX = dev_ctx.GetCUDAMaxGridDimSize()[0];
|
||||
// actually, int num_rows < max_grid_size
|
||||
int grid_size = num_rows < maxGridDimX ? num_rows : maxGridDimX;
|
||||
FillGrad<<<grid_size, block_size, 0, cu_stream>>>(dO->data<T>(),
|
||||
indices->data<IndType>(),
|
||||
dX->data<T>(),
|
||||
num_rows,
|
||||
num_cols);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ArgFlattenAssign(const GPUContext& dev_ctx,
|
||||
const DenseTensor* dO,
|
||||
const DenseTensor* indices,
|
||||
int64_t size,
|
||||
DenseTensor* dX) {
|
||||
auto cu_stream = dev_ctx.stream();
|
||||
|
||||
const int64_t block_size =
|
||||
std::min(size, static_cast<int64_t>(dev_ctx.GetMaxThreadsPerBlock()));
|
||||
int64_t max_threads = dev_ctx.GetMaxPhysicalThreadCount();
|
||||
const int64_t max_blocks =
|
||||
std::max(((max_threads - 1) / block_size + 1), static_cast<int64_t>(1));
|
||||
const int64_t grid_size =
|
||||
std::min(max_blocks, (size + block_size - 1) / block_size);
|
||||
|
||||
FillFlattenGrad<<<grid_size, block_size, 0, cu_stream>>>(
|
||||
dO->data<T>(), indices->data<int64_t>(), size, dX->data<T>());
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ArgsortGradKernel(const Context& dev_ctx,
|
||||
const DenseTensor& indices,
|
||||
const DenseTensor& input,
|
||||
const DenseTensor& out_grad,
|
||||
int axis,
|
||||
bool descending,
|
||||
bool stable,
|
||||
DenseTensor* in_grad) {
|
||||
dev_ctx.template Alloc<T>(in_grad);
|
||||
funcs::set_constant(dev_ctx, in_grad, static_cast<T>(0.0));
|
||||
if (out_grad.numel() == 0) return;
|
||||
auto in_dims = in_grad->dims();
|
||||
auto rank = in_dims.size();
|
||||
axis = (axis < 0) ? (in_dims.size() + axis) : axis;
|
||||
int64_t size = in_grad->numel();
|
||||
|
||||
if (rank == 0) {
|
||||
Copy<Context>(dev_ctx, out_grad, dev_ctx.GetPlace(), false, in_grad);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parallel acceleration when the input size is equal to the length of the
|
||||
// 'axis' dimension.
|
||||
// Compared to 'special case for full sort' below, the gradient calculation
|
||||
// is 10 times faster.
|
||||
if (size == in_dims[axis]) {
|
||||
ArgFlattenAssign<T>(dev_ctx, &out_grad, &indices, size, in_grad);
|
||||
return;
|
||||
}
|
||||
|
||||
// Special case for full sort, speedup ~190x.
|
||||
if (axis == -1 || axis + 1 == in_dims.size()) {
|
||||
const int64_t input_height =
|
||||
common::product(slice_ddim(in_dims, 0, in_dims.size() - 1));
|
||||
const int64_t input_width = in_dims[in_dims.size() - 1];
|
||||
ArgFullAssign<T, int64_t>(
|
||||
dev_ctx, &out_grad, &indices, in_grad, input_height, input_width);
|
||||
} else {
|
||||
// if not full sort, do transpose first
|
||||
std::vector<int> trans;
|
||||
for (int i = 0; i < axis; i++) {
|
||||
trans.push_back(i);
|
||||
}
|
||||
trans.push_back(in_dims.size() - 1);
|
||||
for (int i = axis + 1; i < in_dims.size() - 1; i++) {
|
||||
trans.push_back(i);
|
||||
}
|
||||
trans.push_back(axis);
|
||||
DDim trans_dims(in_dims);
|
||||
for (int i = 0; i < trans.size(); i++) {
|
||||
trans_dims[i] = in_dims[trans[i]];
|
||||
}
|
||||
|
||||
DenseTensor trans_dO;
|
||||
trans_dO.Resize(trans_dims);
|
||||
dev_ctx.template Alloc<T>(&trans_dO);
|
||||
DenseTensor trans_ind;
|
||||
trans_ind.Resize(trans_dims);
|
||||
dev_ctx.template Alloc<int64_t>(&trans_ind);
|
||||
TransposeKernel<T, Context>(dev_ctx, out_grad, trans, &trans_dO);
|
||||
TransposeKernel<int64_t, Context>(dev_ctx, indices, trans, &trans_ind);
|
||||
|
||||
const int64_t input_height =
|
||||
common::product(slice_ddim(trans_dims, 0, trans_dims.size() - 1));
|
||||
const int64_t input_width = trans_dims[trans_dims.size() - 1];
|
||||
|
||||
DenseTensor tmp_out;
|
||||
tmp_out.Resize(trans_dims);
|
||||
dev_ctx.template Alloc<T>(&tmp_out);
|
||||
|
||||
ArgFullAssign<T, int64_t>(
|
||||
dev_ctx, &trans_dO, &trans_ind, &tmp_out, input_height, input_width);
|
||||
|
||||
// transpose back
|
||||
TransposeKernel<T, Context>(dev_ctx, tmp_out, trans, in_grad);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(argsort_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ArgsortGradKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
uint8_t,
|
||||
int16_t,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,512 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/argsort_kernel.h"
|
||||
|
||||
#include <thrust/copy.h>
|
||||
#include <thrust/execution_policy.h>
|
||||
#include <thrust/sequence.h>
|
||||
#include <thrust/sort.h>
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_info.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_launch_config.h"
|
||||
#include "paddle/phi/common/memory_utils.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/blas/blas.h"
|
||||
#include "paddle/phi/kernels/funcs/cub.h"
|
||||
#include "paddle/phi/kernels/funcs/math_function.h"
|
||||
#include "paddle/phi/kernels/primitive/functor_primitives.h"
|
||||
#include "paddle/phi/kernels/transpose_kernel.h"
|
||||
|
||||
#ifdef __HIPCC__
|
||||
#include <rocprim/config.hpp>
|
||||
#if defined(ROCPRIM_VERSION) && ROCPRIM_VERSION >= 400000
|
||||
// rocPRIM 4.x (ROCm 7.0+) replaces detail::radix_key_codec_base
|
||||
// with traits::define for non-builtin / wrapper types.
|
||||
namespace rocprim {
|
||||
namespace traits {
|
||||
template <>
|
||||
struct define<phi::float16> {
|
||||
using float_bit_mask =
|
||||
float_bit_mask::values<uint16_t, 0x8000, 0x7C00, 0x03FF>;
|
||||
};
|
||||
template <>
|
||||
struct define<phi::bfloat16> {
|
||||
using float_bit_mask =
|
||||
float_bit_mask::values<uint16_t, 0x8000, 0x7F80, 0x007F>;
|
||||
};
|
||||
} // namespace traits
|
||||
} // namespace rocprim
|
||||
#else
|
||||
namespace rocprim {
|
||||
namespace detail {
|
||||
template <>
|
||||
struct radix_key_codec_base<phi::float16>
|
||||
: radix_key_codec_integral<phi::float16, uint16_t> {};
|
||||
|
||||
template <>
|
||||
struct radix_key_codec_base<phi::bfloat16>
|
||||
: radix_key_codec_integral<phi::bfloat16, uint16_t> {};
|
||||
|
||||
#if HIP_VERSION >= 50400000
|
||||
template <>
|
||||
struct float_bit_mask<phi::float16> : float_bit_mask<rocprim::half> {};
|
||||
|
||||
template <>
|
||||
struct float_bit_mask<phi::bfloat16> : float_bit_mask<rocprim::bfloat16> {};
|
||||
#endif
|
||||
} // namespace detail
|
||||
} // namespace rocprim
|
||||
#endif // ROCPRIM_VERSION
|
||||
#else
|
||||
// set cub base traits in order to handle float16
|
||||
namespace cub {
|
||||
template <>
|
||||
struct NumericTraits<phi::float16>
|
||||
: BaseTraits<FLOATING_POINT, true, false, uint16_t, phi::float16> {};
|
||||
|
||||
template <>
|
||||
struct NumericTraits<phi::bfloat16>
|
||||
: BaseTraits<FLOATING_POINT, true, false, uint16_t, phi::bfloat16> {};
|
||||
} // namespace cub
|
||||
|
||||
#endif
|
||||
|
||||
namespace phi {
|
||||
|
||||
// Iter for move to next row
|
||||
struct SegmentOffsetIter {
|
||||
EIGEN_DEVICE_FUNC
|
||||
explicit SegmentOffsetIter(int num_cols) : num_cols_(num_cols) {}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE int operator()(int idx) const {
|
||||
return idx * num_cols_;
|
||||
}
|
||||
|
||||
int num_cols_;
|
||||
};
|
||||
|
||||
template <typename T, typename IndType>
|
||||
__global__ void merge_kernel(const T* A,
|
||||
size_t sizeA,
|
||||
const T* B,
|
||||
size_t sizeB,
|
||||
const IndType* ids_A,
|
||||
const IndType* ids_B,
|
||||
T* out,
|
||||
IndType* out_ids,
|
||||
bool descending) {
|
||||
int64_t thread =
|
||||
static_cast<int64_t>(blockDim.x) * static_cast<int64_t>(gridDim.x);
|
||||
int64_t num_per_thread = (sizeA + sizeB + thread) / thread;
|
||||
for (int64_t offset = 0; offset < num_per_thread; offset++) {
|
||||
size_t idx =
|
||||
static_cast<size_t>(blockIdx.x) * static_cast<size_t>(blockDim.x) +
|
||||
static_cast<size_t>(threadIdx.x) + offset * thread;
|
||||
size_t total = sizeA + sizeB;
|
||||
if (idx >= total) return;
|
||||
size_t left = (idx > sizeB) ? idx - sizeB : 0;
|
||||
size_t right = (idx < sizeA) ? idx : sizeA;
|
||||
while (left < right) {
|
||||
size_t mid = (left + right) / 2;
|
||||
size_t b_idx = idx - mid;
|
||||
|
||||
T A_mid, B_bidx;
|
||||
if (descending) {
|
||||
A_mid = (mid >= sizeA) ? std::numeric_limits<T>::lowest() : A[mid];
|
||||
B_bidx = (b_idx >= sizeB) ? std::numeric_limits<T>::lowest() : B[b_idx];
|
||||
} else {
|
||||
A_mid = (mid >= sizeA) ? std::numeric_limits<T>::max() : A[mid];
|
||||
B_bidx = (b_idx >= sizeB) ? std::numeric_limits<T>::max() : B[b_idx];
|
||||
}
|
||||
|
||||
if (descending ? (A_mid >= B_bidx) : (A_mid <= B_bidx))
|
||||
left = mid + 1;
|
||||
else
|
||||
right = mid;
|
||||
}
|
||||
|
||||
size_t a_idx = left;
|
||||
size_t b_idx = idx - a_idx;
|
||||
if (a_idx >= sizeA) {
|
||||
if (descending ? (A[sizeA - 1] < B[b_idx]) : (A[sizeA - 1] > B[b_idx])) {
|
||||
out[idx] = A[sizeA - 1];
|
||||
out_ids[idx] = ids_A[sizeA - 1];
|
||||
} else {
|
||||
out[idx] = B[b_idx];
|
||||
out_ids[idx] = ids_B[b_idx];
|
||||
}
|
||||
} else if (b_idx >= sizeB) {
|
||||
out[idx] = A[a_idx];
|
||||
out_ids[idx] = ids_A[a_idx];
|
||||
} else {
|
||||
if (descending ? (A[a_idx] >= B[b_idx]) : (A[a_idx] <= B[b_idx])) {
|
||||
out[idx] = A[a_idx];
|
||||
out_ids[idx] = ids_A[a_idx];
|
||||
} else if (descending ? (a_idx > 0 && (A[a_idx - 1] < B[b_idx]))
|
||||
: (a_idx > 0 && (A[a_idx - 1] > B[b_idx]))) {
|
||||
out[idx] = A[a_idx - 1];
|
||||
out_ids[idx] = ids_A[a_idx - 1];
|
||||
} else {
|
||||
out[idx] = B[b_idx];
|
||||
out_ids[idx] = ids_B[b_idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static __global__ void FillIndex(T* indices, T num_rows, T num_cols) {
|
||||
int col_id = threadIdx.x;
|
||||
int row_id = blockIdx.x;
|
||||
|
||||
for (T j = row_id; j < num_rows; j += gridDim.x) {
|
||||
for (T i = col_id; i < num_cols; i += blockDim.x) {
|
||||
indices[j * num_cols + i] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define CUB_ARGSORT_WRAPPER(func, ...) \
|
||||
{ \
|
||||
size_t temp_storage_bytes = 0; \
|
||||
PADDLE_ENFORCE_GPU_SUCCESS( \
|
||||
func(nullptr, temp_storage_bytes, __VA_ARGS__)); \
|
||||
DenseTensor temp_storage; \
|
||||
int64_t temp_size = static_cast<int64_t>(temp_storage_bytes); \
|
||||
PADDLE_ENFORCE_GT( \
|
||||
temp_size, \
|
||||
0, \
|
||||
common::errors::InvalidArgument( \
|
||||
"Argsort temp storage size is %d, but should be greater than 0.", \
|
||||
temp_size)); \
|
||||
temp_storage.Resize({temp_size}); \
|
||||
dev_ctx.template Alloc<uint8_t>(&temp_storage); \
|
||||
PADDLE_ENFORCE_GPU_SUCCESS( \
|
||||
func(temp_storage.data<uint8_t>(), temp_storage_bytes, __VA_ARGS__)); \
|
||||
}
|
||||
|
||||
#define PREDICATE_CUB_ARGSORT(predicate, if_func, else_func, ...) \
|
||||
if (predicate) \
|
||||
CUB_ARGSORT_WRAPPER(if_func, __VA_ARGS__) \
|
||||
else \
|
||||
CUB_ARGSORT_WRAPPER(else_func, __VA_ARGS__)
|
||||
|
||||
// Sort by flag descending, True: descending. False: Ascending.
|
||||
// Default is false.
|
||||
template <typename T, typename IndType>
|
||||
void ArgFullSort(const GPUContext& dev_ctx,
|
||||
const DenseTensor* input,
|
||||
DenseTensor* output,
|
||||
DenseTensor* indices,
|
||||
const int64_t num_rows,
|
||||
const int64_t num_cols,
|
||||
const bool descending) {
|
||||
PADDLE_ENFORCE_LE_INT_MAX(num_cols, "num_cols");
|
||||
|
||||
auto cu_stream = dev_ctx.stream();
|
||||
auto ComputeBlockSize = [](IndType col) {
|
||||
if (col > 512)
|
||||
return 1024;
|
||||
else if (col > 256 && col <= 512)
|
||||
return 512;
|
||||
else if (col > 128 && col <= 256)
|
||||
return 256;
|
||||
else
|
||||
return 128;
|
||||
};
|
||||
const int block_size = ComputeBlockSize(num_cols);
|
||||
const int64_t maxGridDimX = dev_ctx.GetCUDAMaxGridDimSize()[0];
|
||||
|
||||
const T* inp = input->data<T>();
|
||||
IndType* sorted_indices_ptr = indices->data<IndType>();
|
||||
|
||||
// create iter for counting input
|
||||
cub::CountingInputIterator<IndType> counting_iter(0);
|
||||
// segment_offset is used for move to next row
|
||||
cub::TransformInputIterator<IndType,
|
||||
SegmentOffsetIter,
|
||||
cub::CountingInputIterator<IndType>>
|
||||
segment_offsets_t(counting_iter, SegmentOffsetIter(num_cols));
|
||||
|
||||
// num_rows is the total segments to be sorted
|
||||
constexpr int64_t max_elements = 1 << 30;
|
||||
const int64_t total_elements = num_cols * num_rows;
|
||||
const int64_t segment_size = num_cols;
|
||||
const int64_t element_per_call = std::min(max_elements, total_elements);
|
||||
|
||||
// make sure element_per_call >= segment_size
|
||||
const int64_t adjusted_elements_per_call =
|
||||
std::max(max_elements, segment_size);
|
||||
|
||||
// make sure batch size is the multiple of segment_size
|
||||
const int64_t batch_size =
|
||||
(adjusted_elements_per_call / segment_size) * segment_size;
|
||||
int64_t offset = 0;
|
||||
DenseTensor input_indices;
|
||||
|
||||
T* sorted_out_ptr = sorted_out_ptr = output->data<T>();
|
||||
IndType* ind_ptr = nullptr;
|
||||
|
||||
while (offset < total_elements) {
|
||||
const int64_t n_elements = std::min(batch_size, total_elements - offset);
|
||||
const int64_t n_segments = n_elements / segment_size;
|
||||
|
||||
// allocate a temporary storage for input indices, with shape:
|
||||
// [num_segments = n_elements / segment_size, segment_size]
|
||||
// will be de-allocated once the sort is done, to save memory and
|
||||
// avoid repeated allocation and deallocation
|
||||
if (input_indices.initialized()) {
|
||||
ind_ptr = input_indices.data<IndType>();
|
||||
} else {
|
||||
input_indices.Resize({n_segments, segment_size});
|
||||
ind_ptr = dev_ctx.template Alloc<IndType>(&input_indices);
|
||||
}
|
||||
const int64_t grid_size = std::min(n_segments, maxGridDimX);
|
||||
// Init a index array
|
||||
FillIndex<<<grid_size, block_size, 0, cu_stream>>>(
|
||||
ind_ptr, n_segments, segment_size);
|
||||
|
||||
PREDICATE_CUB_ARGSORT(descending,
|
||||
cub::DeviceSegmentedRadixSort::SortPairsDescending,
|
||||
cub::DeviceSegmentedRadixSort::SortPairs,
|
||||
inp + offset,
|
||||
sorted_out_ptr + offset,
|
||||
ind_ptr,
|
||||
sorted_indices_ptr + offset,
|
||||
n_elements,
|
||||
n_segments,
|
||||
segment_offsets_t,
|
||||
segment_offsets_t + 1,
|
||||
0,
|
||||
sizeof(T) * 8,
|
||||
cu_stream);
|
||||
offset += n_elements;
|
||||
}
|
||||
}
|
||||
template <typename T, typename IndType>
|
||||
void PerSort(const GPUContext& dev_ctx,
|
||||
T* out_data,
|
||||
int64_t* ids_data,
|
||||
IndType start,
|
||||
IndType end,
|
||||
bool stable,
|
||||
bool descending) {
|
||||
#ifdef PADDLE_WITH_CUDA
|
||||
phi::memory_utils::ThrustAllocator<cudaStream_t> allocator(dev_ctx.GetPlace(),
|
||||
dev_ctx.stream());
|
||||
const auto& exec_policy = thrust::cuda::par(allocator).on(dev_ctx.stream());
|
||||
#else
|
||||
phi::memory_utils::ThrustAllocator<hipStream_t> allocator(dev_ctx.GetPlace(),
|
||||
dev_ctx.stream());
|
||||
const auto& exec_policy = thrust::hip::par(allocator).on(dev_ctx.stream());
|
||||
#endif
|
||||
if (stable) {
|
||||
if (descending) {
|
||||
thrust::stable_sort_by_key(exec_policy,
|
||||
out_data + start,
|
||||
out_data + end,
|
||||
ids_data + start,
|
||||
thrust::greater<T>());
|
||||
} else {
|
||||
thrust::stable_sort_by_key(
|
||||
exec_policy, out_data + start, out_data + end, ids_data + start);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
thrust::sort_by_key(
|
||||
exec_policy, out_data + start, out_data + end, ids_data + start);
|
||||
if (descending) {
|
||||
thrust::reverse(exec_policy, out_data + start, out_data + end);
|
||||
thrust::reverse(exec_policy, ids_data + start, ids_data + end);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ArgsortKernel(const Context& dev_ctx,
|
||||
const DenseTensor& input,
|
||||
int axis,
|
||||
bool descending,
|
||||
bool stable,
|
||||
DenseTensor* output,
|
||||
DenseTensor* indices) {
|
||||
auto in_dims = input.dims();
|
||||
auto rank = in_dims.size();
|
||||
|
||||
if (input.numel() == 0) {
|
||||
output->Resize(in_dims);
|
||||
indices->Resize(in_dims);
|
||||
dev_ctx.template Alloc<T>(output);
|
||||
dev_ctx.template Alloc<int64_t>(indices);
|
||||
return;
|
||||
}
|
||||
|
||||
axis = (axis < 0) ? (in_dims.size() + axis) : axis;
|
||||
const T* in_data = input.data<T>();
|
||||
auto size = input.numel();
|
||||
|
||||
if (rank == 0) {
|
||||
dev_ctx.template Alloc<T>(output);
|
||||
dev_ctx.template Alloc<int64_t>(indices);
|
||||
Copy<Context>(dev_ctx, input, dev_ctx.GetPlace(), false, output);
|
||||
funcs::set_constant(dev_ctx, indices, static_cast<int64_t>(0));
|
||||
return;
|
||||
}
|
||||
|
||||
// Use thrust for parallel acceleration when the input size is equal to the
|
||||
// length of the 'axis' dimension.
|
||||
// Compared to the following 'Special case for full sort', ascending sort is
|
||||
// 34 times faster and descending sort is 31 times faster.
|
||||
if (size == in_dims[axis]) {
|
||||
T* out_data = dev_ctx.template Alloc<T>(output);
|
||||
int64_t* ids_data = dev_ctx.template Alloc<int64_t>(indices);
|
||||
#ifdef PADDLE_WITH_CUDA
|
||||
phi::memory_utils::ThrustAllocator<cudaStream_t> allocator(
|
||||
dev_ctx.GetPlace(), dev_ctx.stream());
|
||||
const auto& exec_policy = thrust::cuda::par(allocator).on(dev_ctx.stream());
|
||||
#else
|
||||
phi::memory_utils::ThrustAllocator<hipStream_t> allocator(
|
||||
dev_ctx.GetPlace(), dev_ctx.stream());
|
||||
const auto& exec_policy = thrust::hip::par(allocator).on(dev_ctx.stream());
|
||||
#endif
|
||||
auto cu_stream = dev_ctx.stream();
|
||||
thrust::sequence(exec_policy, ids_data, ids_data + size);
|
||||
thrust::copy(exec_policy, in_data, in_data + size, out_data);
|
||||
const int64_t per_number = (1LL << 31) - 1;
|
||||
int64_t start = 0;
|
||||
int64_t end = std::min(start + per_number, size);
|
||||
if (end == size) {
|
||||
PerSort<T, int64_t>(
|
||||
dev_ctx, out_data, ids_data, start, end, stable, descending);
|
||||
} else {
|
||||
// Sorting the segments and then merging them
|
||||
DenseTensor temp;
|
||||
DenseTensor ids;
|
||||
temp.Resize(in_dims);
|
||||
ids.Resize(in_dims);
|
||||
T* temp_data = dev_ctx.template Alloc<T>(&temp);
|
||||
int64_t* temp_ids = dev_ctx.template Alloc<int64_t>(&ids);
|
||||
|
||||
while (start != size) {
|
||||
PerSort<T, int64_t>(
|
||||
dev_ctx, out_data, ids_data, start, end, stable, descending);
|
||||
if (start != 0) {
|
||||
auto config = backends::gpu::GetGpuLaunchConfig1D(dev_ctx, end);
|
||||
merge_kernel<<<config.block_per_grid.x,
|
||||
config.thread_per_block.x,
|
||||
0,
|
||||
cu_stream>>>(out_data,
|
||||
start,
|
||||
out_data + start,
|
||||
end - start,
|
||||
ids_data,
|
||||
ids_data + start,
|
||||
temp_data,
|
||||
temp_ids,
|
||||
descending);
|
||||
thrust::copy(exec_policy, temp_ids, temp_ids + end, ids_data);
|
||||
thrust::copy(exec_policy, temp_data, temp_data + end, out_data);
|
||||
}
|
||||
start = end;
|
||||
end = std::min(start + per_number, size);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Special case for full sort, speedup ~190x.
|
||||
if (axis == -1 || axis + 1 == in_dims.size()) {
|
||||
const int64_t input_height =
|
||||
common::product(slice_ddim(in_dims, 0, in_dims.size() - 1));
|
||||
const int64_t input_width = in_dims[in_dims.size() - 1];
|
||||
dev_ctx.template Alloc<int64_t>(indices);
|
||||
dev_ctx.template Alloc<T>(output);
|
||||
ArgFullSort<T, int64_t>(dev_ctx,
|
||||
&input,
|
||||
output,
|
||||
indices,
|
||||
input_height,
|
||||
input_width,
|
||||
descending);
|
||||
} else {
|
||||
// if not full sort, do transpose first
|
||||
std::vector<int> trans;
|
||||
for (int i = 0; i < axis; i++) {
|
||||
trans.push_back(i);
|
||||
}
|
||||
trans.push_back(in_dims.size() - 1);
|
||||
for (int i = axis + 1; i < in_dims.size() - 1; i++) {
|
||||
trans.push_back(i);
|
||||
}
|
||||
trans.push_back(axis);
|
||||
DDim trans_dims(in_dims);
|
||||
for (int i = 0; i < trans.size(); i++) {
|
||||
trans_dims[i] = in_dims[trans[i]];
|
||||
}
|
||||
|
||||
DenseTensor trans_inp;
|
||||
trans_inp.Resize(trans_dims);
|
||||
T* trans_inp_data = dev_ctx.template Alloc<T>(&trans_inp);
|
||||
// Do transpose
|
||||
TransposeKernel<T, Context>(dev_ctx, input, trans, &trans_inp);
|
||||
|
||||
const int64_t input_height =
|
||||
common::product(slice_ddim(trans_dims, 0, trans_dims.size() - 1));
|
||||
const int64_t input_width = trans_dims[trans_dims.size() - 1];
|
||||
|
||||
DenseTensor tmp_out;
|
||||
tmp_out.Resize(trans_dims);
|
||||
dev_ctx.template Alloc<T>(&tmp_out);
|
||||
|
||||
DenseTensor tmp_indices;
|
||||
// temp indices for sorting
|
||||
tmp_indices.Resize(trans_dims);
|
||||
dev_ctx.template Alloc<int64_t>(&tmp_indices);
|
||||
|
||||
ArgFullSort<T, int64_t>(dev_ctx,
|
||||
&trans_inp,
|
||||
&tmp_out,
|
||||
&tmp_indices,
|
||||
input_height,
|
||||
input_width,
|
||||
descending);
|
||||
// delay output allocation until after transpose, to avoid
|
||||
// allocating too much memory
|
||||
dev_ctx.template Alloc<T>(output);
|
||||
dev_ctx.template Alloc<int64_t>(indices);
|
||||
// transpose back
|
||||
TransposeKernel<T, Context>(dev_ctx, tmp_out, trans, output);
|
||||
TransposeKernel<int64_t, Context>(dev_ctx, tmp_indices, trans, indices);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(argsort,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ArgsortKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
uint8_t,
|
||||
int16_t,
|
||||
phi::float16,
|
||||
phi::bfloat16) {
|
||||
kernel->OutputAt(1).SetDataType(phi::DataType::INT64);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/as_complex_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/common/type_traits.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/as_complex_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(
|
||||
as_complex, GPU, ALL_LAYOUT, phi::AsComplexKernel, float, double) {
|
||||
kernel->OutputAt(0).SetDataType(phi::dtype::ToComplex(kernel_key.dtype()));
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/as_real_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/as_real_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(as_real,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AsRealKernel,
|
||||
phi::complex64,
|
||||
phi::complex128) {
|
||||
kernel->OutputAt(0).SetDataType(phi::DataType::UNDEFINED);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/asgd_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_helper.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/core/mixed_vector.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename MT>
|
||||
__global__ void ASGDKernelGPUImpl(const T* param,
|
||||
const T* grad,
|
||||
const T* learning_rate,
|
||||
const T* d,
|
||||
const T* y,
|
||||
const T* n,
|
||||
const MT* master_param,
|
||||
int num,
|
||||
T* param_out,
|
||||
T* d_out,
|
||||
T* y_out,
|
||||
MT* master_param_out) {
|
||||
MT learning_rate_MT = static_cast<MT>(learning_rate[0]);
|
||||
MT n_MT = static_cast<MT>(n[0]);
|
||||
CUDA_KERNEL_LOOP_TYPE(i, num, int64_t) {
|
||||
MT param_data = master_param ? master_param[i] : static_cast<MT>(param[i]);
|
||||
MT grad_data = static_cast<MT>(grad[i]);
|
||||
MT d_data = static_cast<MT>(d[i]);
|
||||
MT y_data = static_cast<MT>(y[i]);
|
||||
d_data = d_data - y_data + grad_data;
|
||||
y_data = grad_data;
|
||||
param_data = param_data - (learning_rate_MT / n_MT) * d_data;
|
||||
param_out[i] = static_cast<T>(param_data);
|
||||
d_out[i] = static_cast<T>(d_data);
|
||||
y_out[i] = static_cast<T>(y_data);
|
||||
if (master_param_out) {
|
||||
master_param_out[i] = param_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ASGDKernel(const Context& dev_ctx,
|
||||
const DenseTensor& param,
|
||||
const DenseTensor& grad,
|
||||
const DenseTensor& learning_rate,
|
||||
const DenseTensor& d,
|
||||
const DenseTensor& y,
|
||||
const DenseTensor& n,
|
||||
const optional<DenseTensor>& master_param,
|
||||
bool multi_precision,
|
||||
DenseTensor* param_out,
|
||||
DenseTensor* d_out,
|
||||
DenseTensor* y_out,
|
||||
DenseTensor* master_param_out) {
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
const MT* master_in_data =
|
||||
multi_precision ? master_param->data<MT>() : nullptr;
|
||||
MT* master_out_data =
|
||||
multi_precision ? dev_ctx.template Alloc<MT>(master_param_out) : nullptr;
|
||||
|
||||
int block = 512;
|
||||
int64_t grid_max = dev_ctx.GetCUDAMaxGridDimSize()[0];
|
||||
int grid = std::min((param.numel() + block - 1) / block, grid_max);
|
||||
|
||||
ASGDKernelGPUImpl<T, MT><<<grid, block, 0, dev_ctx.stream()>>>(
|
||||
param.data<T>(),
|
||||
grad.data<T>(),
|
||||
learning_rate.data<T>(),
|
||||
d.data<T>(),
|
||||
y.data<T>(),
|
||||
n.data<T>(),
|
||||
master_in_data,
|
||||
param.numel(),
|
||||
dev_ctx.template Alloc<T>(param_out),
|
||||
dev_ctx.template Alloc<T>(d_out),
|
||||
dev_ctx.template Alloc<T>(y_out),
|
||||
master_out_data);
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(asgd,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ASGDKernel,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
float,
|
||||
double) {}
|
||||
@@ -0,0 +1,89 @@
|
||||
// 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/assign_pos_kernel.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/core/tensor_utils.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
static constexpr int kNumCUDAThreads = 512;
|
||||
static constexpr int64_t kNumMaximumNumBlocks = 4096;
|
||||
|
||||
static inline int NumBlocks(const int64_t N) {
|
||||
return std::min((N + kNumCUDAThreads - 1) / kNumCUDAThreads,
|
||||
kNumMaximumNumBlocks);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void AssignPos(T* cum_count,
|
||||
const T* numbers,
|
||||
T* out,
|
||||
int64_t limit) {
|
||||
CUDA_KERNEL_LOOP(i, limit) {
|
||||
int number_idx = numbers[i];
|
||||
if (number_idx > -1) {
|
||||
int p = CudaAtomicAdd(cum_count + number_idx, -1);
|
||||
out[p - 1] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AssignPosKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const DenseTensor& cum_count,
|
||||
const DenseTensor& eff_num_len,
|
||||
DenseTensor* out) {
|
||||
// assign pos decides which tokens should be fetched belong to specially
|
||||
// counter orderingly.
|
||||
auto cum_count_ptr = &cum_count; // (counter number) int32 | int64
|
||||
auto numbers = &x; // (batch_size * seq_len, topk) int32
|
||||
auto eff_num_len_ptr = &eff_num_len; // (sum(cum_count))
|
||||
auto out_ptr = &out; // (cum_count) value ranges
|
||||
// from 0 to batch_size *
|
||||
// seq_len * topk
|
||||
auto numel = numbers->numel();
|
||||
T* cum_data = const_cast<T*>(cum_count_ptr->data<T>());
|
||||
auto cum_size = cum_count_ptr->numel();
|
||||
|
||||
DenseTensor cpu_eff_num_len;
|
||||
int64_t cpu_eff_num_len_data = 0;
|
||||
bool is_cpu_place = eff_num_len_ptr->place() == CPUPlace();
|
||||
if (is_cpu_place) {
|
||||
cpu_eff_num_len_data = eff_num_len_ptr->data<T>()[0];
|
||||
} else {
|
||||
Copy(dev_ctx, eff_num_len, CPUPlace(), false, &cpu_eff_num_len);
|
||||
cpu_eff_num_len_data = cpu_eff_num_len.data<T>()[0];
|
||||
}
|
||||
|
||||
DDim out_dims = make_ddim({cpu_eff_num_len_data});
|
||||
out->Resize(out_dims);
|
||||
auto out_data = dev_ctx.template Alloc<T>(out);
|
||||
|
||||
const T* num_data = numbers->data<T>();
|
||||
|
||||
int64_t blocks = NumBlocks(numel);
|
||||
int threads = kNumCUDAThreads;
|
||||
|
||||
AssignPos<T><<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
cum_data, num_data, out_data, numel);
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(assign_pos, GPU, ALL_LAYOUT, phi::AssignPosKernel, int64_t) {
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2021 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/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/atan2_grad_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(atan2_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::Atan2GradKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2021 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/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/atan2_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(atan2,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::Atan2Kernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
int,
|
||||
int64_t) {
|
||||
kernel->OutputAt(0).SetDataType(phi::DataType::UNDEFINED);
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/auc_kernel.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
__global__ void ClearObsoleteDataKernel(int64_t *pos,
|
||||
int64_t *neg,
|
||||
const int bucket_length,
|
||||
const int slide_steps) {
|
||||
int cur_step_index =
|
||||
static_cast<int>(pos[(slide_steps + 1) * bucket_length]) % slide_steps;
|
||||
int64_t cur_step_begin = static_cast<int64_t>(cur_step_index) * bucket_length;
|
||||
int64_t sum_step_begin = static_cast<int64_t>(slide_steps) * bucket_length;
|
||||
CUDA_KERNEL_LOOP(i, bucket_length) {
|
||||
pos[sum_step_begin + i] -= pos[cur_step_begin + i];
|
||||
neg[sum_step_begin + i] -= neg[cur_step_begin + i];
|
||||
pos[cur_step_begin + i] = neg[cur_step_begin + i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void UpdateSumDataKernel(int64_t *pos,
|
||||
int64_t *neg,
|
||||
const int bucket_length,
|
||||
const int slide_steps) {
|
||||
int cur_step_index =
|
||||
static_cast<int>(pos[(slide_steps + 1) * bucket_length]) % slide_steps;
|
||||
int64_t cur_step_begin = static_cast<int64_t>(cur_step_index) * bucket_length;
|
||||
int64_t sum_step_begin = static_cast<int64_t>(slide_steps) * bucket_length;
|
||||
CUDA_KERNEL_LOOP(i, bucket_length) {
|
||||
pos[sum_step_begin + i] += pos[cur_step_begin + i];
|
||||
neg[sum_step_begin + i] += neg[cur_step_begin + i];
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void AddDataKernel(const int64_t *label_data,
|
||||
const T *pred_data,
|
||||
const int inference_width,
|
||||
const int num_thresholds,
|
||||
int64_t *pos,
|
||||
int64_t *neg,
|
||||
const int numel,
|
||||
const int slide_steps) {
|
||||
int cur_step_begin = 0;
|
||||
if (slide_steps > 0) {
|
||||
int cur_step_index =
|
||||
static_cast<int>(pos[(slide_steps + 1) * (1 + num_thresholds)]) %
|
||||
slide_steps;
|
||||
cur_step_begin = cur_step_index * (1 + num_thresholds);
|
||||
}
|
||||
CUDA_KERNEL_LOOP(i, numel) {
|
||||
auto predict_data = pred_data[i * inference_width + (inference_width - 1)];
|
||||
PADDLE_ENFORCE(predict_data <= 1, "The predict data must less or equal 1.");
|
||||
PADDLE_ENFORCE(predict_data >= 0,
|
||||
"The predict data must gather or equal 0.");
|
||||
uint32_t binIdx = static_cast<uint32_t>(predict_data * num_thresholds);
|
||||
if (label_data[i]) {
|
||||
CudaAtomicAdd(pos + cur_step_begin + binIdx, 1);
|
||||
} else {
|
||||
CudaAtomicAdd(neg + cur_step_begin + binIdx, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void CalcAucKernel(int64_t *stat_pos,
|
||||
int64_t *stat_neg,
|
||||
int num_thresholds,
|
||||
double *auc,
|
||||
bool need_add_batch_num) {
|
||||
*auc = 0.0f;
|
||||
double totPos = 0.0;
|
||||
double totNeg = 0.0;
|
||||
double totPosPrev = 0.0;
|
||||
double totNegPrev = 0.0;
|
||||
|
||||
int idx = num_thresholds;
|
||||
|
||||
while (idx >= 0) {
|
||||
totPosPrev = totPos;
|
||||
totNegPrev = totNeg;
|
||||
totPos += stat_pos[idx];
|
||||
totNeg += stat_neg[idx];
|
||||
*auc += (totNeg - totNegPrev) * (totPos + totPosPrev) / 2.0;
|
||||
--idx;
|
||||
}
|
||||
|
||||
if (totPos > 0.0 && totNeg > 0.0) {
|
||||
*auc = *auc / totPos / totNeg;
|
||||
}
|
||||
if (need_add_batch_num) {
|
||||
stat_pos[num_thresholds + 1] += 1;
|
||||
stat_neg[num_thresholds + 1] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
inline static double trapezoidArea(double X1, double X2, double Y1, double Y2) {
|
||||
return (X1 > X2 ? (X1 - X2) : (X2 - X1)) * (Y1 + Y2) / 2.0;
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void statAuc(const Context &dev_ctx,
|
||||
const DenseTensor &label,
|
||||
const DenseTensor &predict,
|
||||
const int num_thresholds,
|
||||
const int slide_steps,
|
||||
int64_t *origin_stat_pos,
|
||||
int64_t *origin_stat_neg,
|
||||
const bool is_fake_data) {
|
||||
size_t batch_size = predict.dims()[0];
|
||||
size_t inference_width = predict.dims()[1];
|
||||
const T *inference_data = predict.data<T>();
|
||||
const auto *label_data = label.data<int64_t>();
|
||||
const int bucket_length = num_thresholds + 1;
|
||||
|
||||
if (slide_steps == 0) {
|
||||
AddDataKernel<<<(batch_size + PADDLE_CUDA_NUM_THREADS - 1) /
|
||||
PADDLE_CUDA_NUM_THREADS,
|
||||
PADDLE_CUDA_NUM_THREADS,
|
||||
0,
|
||||
dev_ctx.stream()>>>(label_data,
|
||||
inference_data,
|
||||
inference_width,
|
||||
num_thresholds,
|
||||
origin_stat_pos,
|
||||
origin_stat_neg,
|
||||
batch_size,
|
||||
slide_steps);
|
||||
return;
|
||||
}
|
||||
// the last number of origin_stat_pos store the index should be used in
|
||||
// current step
|
||||
int cur_step_index =
|
||||
static_cast<int>(origin_stat_pos[(slide_steps + 1) * bucket_length]) %
|
||||
slide_steps;
|
||||
int64_t cur_step_begin = static_cast<int64_t>(cur_step_index) * bucket_length;
|
||||
int64_t sum_step_begin = static_cast<int64_t>(slide_steps) * bucket_length;
|
||||
|
||||
ClearObsoleteDataKernel<<<(bucket_length + PADDLE_CUDA_NUM_THREADS - 1) /
|
||||
PADDLE_CUDA_NUM_THREADS,
|
||||
PADDLE_CUDA_NUM_THREADS,
|
||||
0,
|
||||
dev_ctx.stream()>>>(
|
||||
origin_stat_pos, origin_stat_neg, bucket_length, slide_steps);
|
||||
|
||||
AddDataKernel<<<(batch_size + PADDLE_CUDA_NUM_THREADS - 1) /
|
||||
PADDLE_CUDA_NUM_THREADS,
|
||||
PADDLE_CUDA_NUM_THREADS,
|
||||
0,
|
||||
dev_ctx.stream()>>>(label_data,
|
||||
inference_data,
|
||||
inference_width,
|
||||
num_thresholds,
|
||||
origin_stat_pos,
|
||||
origin_stat_neg,
|
||||
batch_size,
|
||||
slide_steps);
|
||||
if (!is_fake_data) {
|
||||
UpdateSumDataKernel<<<(bucket_length + PADDLE_CUDA_NUM_THREADS - 1) /
|
||||
PADDLE_CUDA_NUM_THREADS,
|
||||
PADDLE_CUDA_NUM_THREADS,
|
||||
0,
|
||||
dev_ctx.stream()>>>(
|
||||
origin_stat_pos, origin_stat_neg, bucket_length, slide_steps);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void AucKernel(const Context &dev_ctx,
|
||||
const DenseTensor &input,
|
||||
const DenseTensor &label,
|
||||
const DenseTensor &stat_pos,
|
||||
const DenseTensor &stat_neg,
|
||||
const optional<DenseTensor> &ins_tag_weight,
|
||||
const std::string &curve,
|
||||
int num_thresholds,
|
||||
int slide_steps,
|
||||
DenseTensor *auc,
|
||||
DenseTensor *stat_pos_out,
|
||||
DenseTensor *stat_neg_out) {
|
||||
// Only use output var for now, make sure it's persistable and
|
||||
// not cleaned up for each batch.
|
||||
auto *origin_stat_pos = dev_ctx.template Alloc<int64_t>(stat_pos_out);
|
||||
auto *origin_stat_neg = dev_ctx.template Alloc<int64_t>(stat_neg_out);
|
||||
auto *auc_value = dev_ctx.template Alloc<double>(auc);
|
||||
|
||||
auto *stat_pos_in_tensor = &stat_pos;
|
||||
auto *stat_neg_in_tensor = &stat_neg;
|
||||
auto *pos_in_data = stat_pos.data<int64_t>();
|
||||
auto *neg_in_data = stat_neg.data<int64_t>();
|
||||
bool is_fake_data = false;
|
||||
if (ins_tag_weight.get_ptr() != nullptr) {
|
||||
const auto *ins_tag_weight_data = ins_tag_weight->data<float>();
|
||||
if (ins_tag_weight_data[0] == 0) {
|
||||
is_fake_data = true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PADDLE_WITH_CUDA
|
||||
if (stat_pos_in_tensor != stat_pos_out) {
|
||||
cudaMemcpyAsync(
|
||||
origin_stat_pos,
|
||||
pos_in_data,
|
||||
((1 + slide_steps) * (num_thresholds + 1) + (slide_steps > 0 ? 1 : 0)) *
|
||||
sizeof(int64_t),
|
||||
cudaMemcpyDeviceToDevice,
|
||||
dev_ctx.stream());
|
||||
}
|
||||
if (stat_neg_in_tensor != stat_neg_out) {
|
||||
cudaMemcpyAsync(
|
||||
origin_stat_neg,
|
||||
neg_in_data,
|
||||
((1 + slide_steps) * (num_thresholds + 1) + (slide_steps > 0 ? 1 : 0)) *
|
||||
sizeof(int64_t),
|
||||
cudaMemcpyDeviceToDevice,
|
||||
dev_ctx.stream());
|
||||
}
|
||||
#else
|
||||
if (stat_pos_in_tensor != stat_pos_out) {
|
||||
hipMemcpy(
|
||||
origin_stat_pos,
|
||||
pos_in_data,
|
||||
((1 + slide_steps) * (num_thresholds + 1) + (slide_steps > 0 ? 1 : 0)) *
|
||||
sizeof(int64_t),
|
||||
hipMemcpyDeviceToDevice);
|
||||
}
|
||||
if (stat_neg_in_tensor != stat_neg_out) {
|
||||
hipMemcpy(
|
||||
origin_stat_neg,
|
||||
neg_in_data,
|
||||
((1 + slide_steps) * (num_thresholds + 1) + (slide_steps > 0 ? 1 : 0)) *
|
||||
sizeof(int64_t),
|
||||
hipMemcpyDeviceToDevice);
|
||||
}
|
||||
#endif
|
||||
|
||||
// when calculate global_auc && is fake data, just do nothing
|
||||
if (slide_steps == 0 && is_fake_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
statAuc<T, Context>(dev_ctx,
|
||||
label,
|
||||
input,
|
||||
num_thresholds,
|
||||
slide_steps,
|
||||
origin_stat_pos,
|
||||
origin_stat_neg,
|
||||
is_fake_data);
|
||||
int64_t sum_offset = static_cast<int64_t>(slide_steps) * (num_thresholds + 1);
|
||||
CalcAucKernel<<<1, 1, 0, dev_ctx.stream()>>>(origin_stat_pos + sum_offset,
|
||||
origin_stat_neg + sum_offset,
|
||||
num_thresholds,
|
||||
auc_value,
|
||||
slide_steps > 0);
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(auc, GPU, ALL_LAYOUT, phi::AucKernel, float) {
|
||||
kernel->OutputAt(0).SetDataType(phi::DataType::FLOAT64);
|
||||
kernel->OutputAt(1).SetDataType(phi::DataType::INT64);
|
||||
kernel->OutputAt(2).SetDataType(phi::DataType::INT64);
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/* Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. */
|
||||
|
||||
#include "paddle/phi/kernels/average_accumulates_kernel.h"
|
||||
#include "paddle/phi/kernels/impl/average_accumulates_kernel_impl.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/cuda/cuda_graph_with_memory_pool.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <>
|
||||
void GetAccumulators<GPUContext>(const GPUContext& dev_ctx,
|
||||
const DenseTensor& in_num_accumulates,
|
||||
const DenseTensor& in_old_num_accumulates,
|
||||
const DenseTensor& in_num_updates,
|
||||
int64_t* num_updates,
|
||||
int64_t* num_accumulates,
|
||||
int64_t* old_num_accumulates) {
|
||||
auto stream = dev_ctx.stream();
|
||||
auto cuda_place = in_old_num_accumulates.place();
|
||||
memory_utils::Copy(CPUPlace(),
|
||||
old_num_accumulates,
|
||||
cuda_place,
|
||||
in_old_num_accumulates.data<int64_t>(),
|
||||
sizeof(int64_t),
|
||||
stream);
|
||||
memory_utils::Copy(CPUPlace(),
|
||||
num_accumulates,
|
||||
cuda_place,
|
||||
in_num_accumulates.data<int64_t>(),
|
||||
sizeof(int64_t),
|
||||
stream);
|
||||
memory_utils::Copy(CPUPlace(),
|
||||
num_updates,
|
||||
cuda_place,
|
||||
in_num_updates.data<int64_t>(),
|
||||
sizeof(int64_t),
|
||||
stream);
|
||||
}
|
||||
|
||||
template <>
|
||||
void SetAccumulators<GPUContext>(const GPUContext& dev_ctx,
|
||||
int64_t num_updates,
|
||||
int64_t num_accumulates,
|
||||
int64_t old_num_accumulates,
|
||||
DenseTensor* out_num_accumulates,
|
||||
DenseTensor* out_old_num_accumulates,
|
||||
DenseTensor* out_num_updates) {
|
||||
int64_t* out_num_accumulates_ptr =
|
||||
dev_ctx.template Alloc<int64_t>(out_num_accumulates);
|
||||
int64_t* out_old_num_accumulates_ptr =
|
||||
dev_ctx.template Alloc<int64_t>(out_old_num_accumulates);
|
||||
int64_t* out_num_updates_ptr =
|
||||
dev_ctx.template Alloc<int64_t>(out_num_updates);
|
||||
|
||||
auto stream = dev_ctx.stream();
|
||||
|
||||
auto cuda_place = out_old_num_accumulates->place();
|
||||
const int64_t* stable_na =
|
||||
backends::gpu::RestoreHostMemIfCapturingCUDAGraph(&num_accumulates, 1);
|
||||
memory_utils::Copy(dev_ctx.GetPlace(),
|
||||
out_num_accumulates_ptr,
|
||||
CPUPlace(),
|
||||
stable_na,
|
||||
sizeof(int64_t),
|
||||
stream);
|
||||
|
||||
const int64_t* stable_ona = backends::gpu::RestoreHostMemIfCapturingCUDAGraph(
|
||||
&old_num_accumulates, 1);
|
||||
memory_utils::Copy(dev_ctx.GetPlace(),
|
||||
out_old_num_accumulates_ptr,
|
||||
CPUPlace(),
|
||||
stable_ona,
|
||||
sizeof(int64_t),
|
||||
stream);
|
||||
|
||||
const int64_t* stable_nu =
|
||||
backends::gpu::RestoreHostMemIfCapturingCUDAGraph(&num_updates, 1);
|
||||
memory_utils::Copy(cuda_place,
|
||||
out_num_updates_ptr,
|
||||
CPUPlace(),
|
||||
stable_nu,
|
||||
sizeof(int64_t),
|
||||
stream);
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(average_accumulates,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::AverageAccumulatesKernel,
|
||||
float,
|
||||
double) {
|
||||
kernel->OutputAt(3).SetDataType(phi::DataType::INT64);
|
||||
kernel->OutputAt(4).SetDataType(phi::DataType::INT64);
|
||||
kernel->OutputAt(5).SetDataType(phi::DataType::INT64);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/* Copyright (c) 2025 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/baddbmm_grad_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/baddbmm_grad_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(baddbmm_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::BaddbmmGradKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,28 @@
|
||||
/* Copyright (c) 2025 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/baddbmm_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/baddbmm_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(baddbmm,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::BaddbmmKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2024 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/barrier_kernel.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
#include "paddle/phi/core/distributed/nccl_comm_context.h"
|
||||
#endif
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void BarrierKernel(const Context &dev_ctx,
|
||||
const DenseTensor &x,
|
||||
DenseTensor *out) {
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
auto in = &x;
|
||||
auto comm_ctx =
|
||||
static_cast<distributed::NCCLCommContext *>(dev_ctx.GetCommContext());
|
||||
PADDLE_ENFORCE_NE(comm_ctx,
|
||||
nullptr,
|
||||
common::errors::Unavailable(
|
||||
"NCCLCommContext is nullptr, collective op should "
|
||||
"has ring_id attr."));
|
||||
auto stream = comm_ctx->GetStream();
|
||||
ncclRedOp_t nccl_red_type = ncclSum;
|
||||
comm_ctx->AllReduce(out, *in, nccl_red_type, stream);
|
||||
backends::gpu::GpuStreamSync(stream);
|
||||
#else
|
||||
PADDLE_THROW(
|
||||
common::errors::Unavailable("PaddlePaddle should compile with NCCL."));
|
||||
#endif
|
||||
}
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(barrier, GPU, ALL_LAYOUT, phi::BarrierKernel, int) {}
|
||||
@@ -0,0 +1,150 @@
|
||||
// Copyright (c) 2024 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 <string>
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_info.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/blas/blas.h"
|
||||
#include "paddle/phi/kernels/funcs/eigen/common.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
const int CUDA_NUM_THREADS = 1024;
|
||||
static inline int GET_BLOCKS(const int N) {
|
||||
return (N + CUDA_NUM_THREADS - 1) / CUDA_NUM_THREADS;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void add_bias_grad_kernel(const T* dout_data,
|
||||
int slot_pairs_num,
|
||||
int ins_num,
|
||||
int out_dim,
|
||||
T* db_data) {
|
||||
CUDA_KERNEL_LOOP(idx, slot_pairs_num * out_dim) {
|
||||
int row = idx / out_dim;
|
||||
int col = idx % out_dim;
|
||||
T temp = static_cast<T>(0);
|
||||
for (int i = 0; i < ins_num; ++i) {
|
||||
int select_index = ((row + 1) * i + 1) * col;
|
||||
temp += dout_data[select_index];
|
||||
}
|
||||
db_data[idx] += temp;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void add_bias_grad(gpuStream_t stream,
|
||||
const T* dout_data,
|
||||
int slot_pairs_num,
|
||||
int ins_num,
|
||||
int out_dim,
|
||||
T* db_data) {
|
||||
add_bias_grad_kernel<<<GET_BLOCKS(slot_pairs_num * out_dim),
|
||||
CUDA_NUM_THREADS,
|
||||
0,
|
||||
stream>>>(
|
||||
dout_data, slot_pairs_num, ins_num, out_dim, db_data);
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void BatchFCGradOpCUDAKernel(const Context& dev_ctx,
|
||||
const DenseTensor& input_in,
|
||||
const DenseTensor& w_in,
|
||||
const DenseTensor& bias_in UNUSED,
|
||||
const DenseTensor& out_grad,
|
||||
DenseTensor* input_grad,
|
||||
DenseTensor* w_grad,
|
||||
DenseTensor* bias_grad) {
|
||||
auto* input = &input_in;
|
||||
auto* w = &w_in;
|
||||
auto* dout = &out_grad;
|
||||
|
||||
auto* dx = input_grad;
|
||||
auto* dw = w_grad;
|
||||
auto* db = bias_grad;
|
||||
|
||||
auto input_dims = input->dims();
|
||||
auto w_dims = w->dims();
|
||||
auto slot_pairs_num = input_dims[0];
|
||||
auto ins_num = input_dims[1];
|
||||
auto in_dim = input_dims[2];
|
||||
auto out_dim = w_dims[2];
|
||||
|
||||
auto& place = *dev_ctx.eigen_device();
|
||||
// initialize
|
||||
dev_ctx.template Alloc<T>(dx);
|
||||
auto dx_eigen = EigenVector<T>::Flatten(*dx);
|
||||
dx_eigen.device(place) = dx_eigen.constant(static_cast<T>(0));
|
||||
|
||||
dev_ctx.template Alloc<T>(dw);
|
||||
auto dw_eigen = EigenVector<T>::Flatten(*dw);
|
||||
dw_eigen.device(place) = dw_eigen.constant(static_cast<T>(0));
|
||||
|
||||
// get data ptr
|
||||
const T* x_data = input->data<T>();
|
||||
const T* w_data = w->data<T>();
|
||||
const T* dout_data = dout->data<T>();
|
||||
T* dx_data = dx->data<T>();
|
||||
T* dw_data = dw->data<T>();
|
||||
|
||||
dev_ctx.template Alloc<T>(db);
|
||||
auto db_eigen = EigenVector<T>::Flatten(*db);
|
||||
db_eigen.device(place) = db_eigen.constant(static_cast<T>(0));
|
||||
T* db_data = db->data<T>();
|
||||
add_bias_grad<T>(
|
||||
dev_ctx.stream(), dout_data, slot_pairs_num, ins_num, out_dim, db_data);
|
||||
|
||||
auto blas = funcs::GetBlas<GPUContext, T>(dev_ctx);
|
||||
T alpha = 1;
|
||||
T beta = 0;
|
||||
|
||||
// dx = dout_data * y^T
|
||||
blas.BatchedGEMM(CblasNoTrans,
|
||||
CblasTrans,
|
||||
ins_num,
|
||||
in_dim,
|
||||
out_dim,
|
||||
alpha,
|
||||
dout_data,
|
||||
w_data,
|
||||
beta,
|
||||
dx_data,
|
||||
slot_pairs_num,
|
||||
ins_num * out_dim,
|
||||
out_dim * in_dim);
|
||||
// dy = x^T * dout_data
|
||||
blas.BatchedGEMM(CblasTrans,
|
||||
CblasNoTrans,
|
||||
in_dim,
|
||||
out_dim,
|
||||
ins_num,
|
||||
alpha,
|
||||
x_data,
|
||||
dout_data,
|
||||
beta,
|
||||
dw_data,
|
||||
slot_pairs_num,
|
||||
in_dim * ins_num,
|
||||
ins_num * out_dim);
|
||||
}
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(batch_fc_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::BatchFCGradOpCUDAKernel,
|
||||
float,
|
||||
double) {}
|
||||
@@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2024 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 <string>
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_info.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/blas/blas.h"
|
||||
#include "paddle/phi/kernels/funcs/eigen/common.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
const int CUDA_NUM_THREADS = 1024;
|
||||
static inline int GET_BLOCKS(const int N) {
|
||||
return (N + CUDA_NUM_THREADS - 1) / CUDA_NUM_THREADS;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void add_bias_kernel(
|
||||
T* data, int slot_pairs_num, int ins_num, int out_dim, const T* bias) {
|
||||
CUDA_KERNEL_LOOP(idx, slot_pairs_num * ins_num * out_dim) {
|
||||
int block_len = ins_num * out_dim;
|
||||
int slot_index = idx / block_len;
|
||||
int out_dim_index = (idx % block_len) % out_dim;
|
||||
T temp = data[idx] + bias[slot_index * out_dim + out_dim_index];
|
||||
data[idx] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void add_bias(gpuStream_t stream,
|
||||
T* data,
|
||||
int slot_pairs_num,
|
||||
int ins_num,
|
||||
int out_dim,
|
||||
const T* bias) {
|
||||
add_bias_kernel<<<GET_BLOCKS(slot_pairs_num * ins_num * out_dim),
|
||||
CUDA_NUM_THREADS,
|
||||
0,
|
||||
stream>>>(data, slot_pairs_num, ins_num, out_dim, bias);
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void BatchFCCUDAKernel(const Context& dev_ctx,
|
||||
const DenseTensor& input_in,
|
||||
const DenseTensor& w_in,
|
||||
const DenseTensor& bias_in,
|
||||
DenseTensor* out) {
|
||||
// X.dim = slot_pairs_num * ins_num * in_dim
|
||||
// W.dim = slot_pairs_num * in_dim * out_dim
|
||||
// b.dim = slot_pairs_num * out_dim
|
||||
// output.dim = slot_pairs_num * ins_num * out_dim
|
||||
auto* input = &input_in;
|
||||
auto* w = &w_in;
|
||||
auto* bias = &bias_in;
|
||||
auto* output = out;
|
||||
auto input_dims = input->dims();
|
||||
auto w_dims = w->dims();
|
||||
auto slot_pairs_num = input_dims[0];
|
||||
auto ins_num = input_dims[1];
|
||||
auto in_dim = input_dims[2];
|
||||
auto out_dim = w_dims[2];
|
||||
|
||||
// get data ptr
|
||||
const T* in_data = input->data<T>();
|
||||
const T* w_data = w->data<T>();
|
||||
const T* bias_data = bias->data<T>();
|
||||
|
||||
output->Resize({slot_pairs_num, ins_num, out_dim});
|
||||
T* out_data = dev_ctx.template Alloc<T>(output);
|
||||
// initialize
|
||||
auto out_eigen = EigenVector<T>::Flatten(*output);
|
||||
auto& place = *dev_ctx.eigen_device();
|
||||
out_eigen.device(place) = out_eigen.constant(static_cast<T>(0));
|
||||
|
||||
CBLAS_TRANSPOSE transA = CblasNoTrans;
|
||||
CBLAS_TRANSPOSE transB = CblasNoTrans;
|
||||
|
||||
T alpha = 1;
|
||||
T beta = 0;
|
||||
int64_t strideA = ins_num * in_dim;
|
||||
int64_t strideB = in_dim * out_dim;
|
||||
|
||||
auto blas = funcs::GetBlas<GPUContext, T>(dev_ctx);
|
||||
blas.BatchedGEMM(transA,
|
||||
transB,
|
||||
ins_num,
|
||||
out_dim,
|
||||
in_dim,
|
||||
alpha,
|
||||
in_data,
|
||||
w_data,
|
||||
beta,
|
||||
out_data,
|
||||
slot_pairs_num,
|
||||
strideA,
|
||||
strideB);
|
||||
add_bias<T>(
|
||||
dev_ctx.stream(), out_data, slot_pairs_num, ins_num, out_dim, bias_data);
|
||||
}
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(
|
||||
batch_fc, GPU, ALL_LAYOUT, phi::BatchFCCUDAKernel, float, double) {}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/bce_loss_grad_kernel.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/common/hostdevice.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/elementwise_base.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T>
|
||||
struct BCELossGradFunctor {
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
MT one = static_cast<MT>(1.0f);
|
||||
MT eps = static_cast<MT>(1e-12);
|
||||
|
||||
HOSTDEVICE inline T operator()(const T x, const T label, const T dout) const {
|
||||
MT x_mt = static_cast<MT>(x);
|
||||
MT term1 = max((one - x_mt) * x_mt, eps);
|
||||
return static_cast<T>(static_cast<MT>(dout) *
|
||||
(x_mt - static_cast<MT>(label)) / term1);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Context>
|
||||
void BCELossGradKernel(const Context& dev_ctx,
|
||||
const DenseTensor& input,
|
||||
const DenseTensor& label,
|
||||
const DenseTensor& out_grad,
|
||||
DenseTensor* input_grad) {
|
||||
dev_ctx.template Alloc<T>(input_grad);
|
||||
std::vector<const DenseTensor*> ins = {&input, &label, &out_grad};
|
||||
std::vector<DenseTensor*> outs = {input_grad};
|
||||
auto functor = BCELossGradFunctor<T>();
|
||||
funcs::ElementwiseKernel<T>(dev_ctx, ins, &outs, functor);
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(bce_loss_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::BCELossGradKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16) {}
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/bce_loss_kernel.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/common/hostdevice.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/elementwise_base.h"
|
||||
#include "paddle/phi/kernels/primitive/functor_primitives.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T>
|
||||
struct BCELossFunctor {
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
MT zero = static_cast<MT>(0);
|
||||
MT one = static_cast<MT>(1.0f);
|
||||
MT neg_100 = static_cast<MT>(-100.);
|
||||
|
||||
HOSTDEVICE inline T operator()(const T x, const T label) const {
|
||||
MT x_mt = static_cast<MT>(x);
|
||||
MT label_mt = static_cast<MT>(label);
|
||||
|
||||
PADDLE_ENFORCE(
|
||||
(x_mt >= zero) && (x_mt <= one),
|
||||
"Input is expected to be within the interval [0, 1], but received %f.",
|
||||
x_mt);
|
||||
|
||||
MT term1 = max(kps::details::Log(x_mt), neg_100);
|
||||
MT term2 = max(kps::details::Log(one - x_mt), neg_100);
|
||||
return static_cast<T>((label_mt - one) * term2 - label_mt * term1);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Context>
|
||||
void BCELossKernel(const Context& dev_ctx,
|
||||
const DenseTensor& input,
|
||||
const DenseTensor& label,
|
||||
DenseTensor* out) {
|
||||
dev_ctx.template Alloc<T>(out);
|
||||
std::vector<const DenseTensor*> ins = {&input, &label};
|
||||
std::vector<DenseTensor*> outs = {out};
|
||||
auto functor = BCELossFunctor<T>();
|
||||
funcs::ElementwiseKernel<T>(dev_ctx, ins, &outs, functor);
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(bce_loss,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::BCELossKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16) {}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2024 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/common/data_type.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/beam_search_decode_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(beam_search_decode,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::BeamSearchDecodeOpKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
int,
|
||||
int64_t) {
|
||||
kernel->OutputAt(0).SetDataType(phi::DataType::INT64);
|
||||
kernel->OutputAt(1).SetDataType(phi::DataType::INT64);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2024 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/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/beam_search_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(beam_search,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::BeamSearchOpKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t) {}
|
||||
@@ -0,0 +1,107 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/bernoulli_kernel.h"
|
||||
|
||||
#ifdef __NVCC__
|
||||
#include <curand_kernel.h>
|
||||
#endif
|
||||
#ifdef __HIPCC__
|
||||
#include <hiprand_kernel.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/common/enforce.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_launch_config.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/distribution_helper.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
// 'curand_uniform4/hiprand_uniform4' generate 4 random number each time
|
||||
template <typename T>
|
||||
__global__ void bernoulli_cuda_kernel(
|
||||
size_t size, uint64_t seed, uint64_t offset, const T* x_data, T* out_data) {
|
||||
size_t thread_idx =
|
||||
static_cast<size_t>(blockIdx.x * blockDim.x + threadIdx.x);
|
||||
|
||||
#if defined(__NVCC__)
|
||||
curandStatePhilox4_32_10_t state;
|
||||
curand_init(seed, thread_idx, offset, &state);
|
||||
#else
|
||||
hiprandStatePhilox4_32_10_t state;
|
||||
hiprand_init(seed, thread_idx, offset, &state);
|
||||
#endif
|
||||
|
||||
size_t total_thread =
|
||||
static_cast<size_t>(gridDim.x) * static_cast<size_t>(blockDim.x);
|
||||
for (size_t i = 4 * thread_idx; i < size; i += total_thread * 4) {
|
||||
funcs::uniform_distribution<float> dist;
|
||||
float4 rand = dist(&state);
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
#pragma unroll
|
||||
for (size_t j = 0; j < 4; j++) {
|
||||
size_t idx = i + j;
|
||||
if (idx < size) {
|
||||
MT p = static_cast<MT>(x_data[idx]);
|
||||
PADDLE_ENFORCE(p >= 0 && p <= 1,
|
||||
"The probability should be in [0, 1], but got %f",
|
||||
p);
|
||||
out_data[idx] = static_cast<T>((&rand.x)[j] <= static_cast<MT>(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void BernoulliKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
DenseTensor* out) {
|
||||
const T* x_data = x.data<T>();
|
||||
T* out_data = dev_ctx.template Alloc<T>(out);
|
||||
auto numel = x.numel();
|
||||
|
||||
auto gen_cuda = dev_ctx.GetGenerator();
|
||||
|
||||
auto seed_offset = gen_cuda->IncrementOffset(12);
|
||||
uint64_t seed = seed_offset.first;
|
||||
uint64_t offset = seed_offset.second;
|
||||
|
||||
auto gpu_config = backends::gpu::GetGpuLaunchConfig1D(dev_ctx, numel, 4);
|
||||
size_t grid_size_64 = gpu_config.GetGridSize();
|
||||
size_t block_size_64 = gpu_config.GetBlockSize();
|
||||
PADDLE_ENFORCE_LE_UINT32_MAX(grid_size_64, "bernoulli grid.x");
|
||||
PADDLE_ENFORCE_LE_UINT32_MAX(block_size_64, "bernoulli block.x");
|
||||
uint32_t grid_size = static_cast<uint32_t>(grid_size_64);
|
||||
uint32_t block_size = static_cast<uint32_t>(block_size_64);
|
||||
|
||||
bernoulli_cuda_kernel<<<grid_size, block_size, 0, dev_ctx.stream()>>>(
|
||||
numel, seed, offset, x_data, out_data);
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(bernoulli,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::BernoulliKernel,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
float,
|
||||
double) {}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/bilinear_grad_kernel.h"
|
||||
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/bilinear_grad_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(
|
||||
bilinear_grad, GPU, ALL_LAYOUT, phi::BilinearGradKernel, float, double) {}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/bilinear_kernel.h"
|
||||
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/bilinear_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(
|
||||
bilinear, GPU, ALL_LAYOUT, phi::BilinearKernel, float, double) {}
|
||||
@@ -0,0 +1,207 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/bincount_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/full_kernel.h"
|
||||
#include "paddle/phi/kernels/funcs/eigen/common.h"
|
||||
#include "paddle/phi/kernels/funcs/math_function.h"
|
||||
namespace phi {
|
||||
|
||||
inline int64_t GET_BLOCKS(const int64_t N) {
|
||||
return (N + PADDLE_CUDA_NUM_THREADS - 1) / PADDLE_CUDA_NUM_THREADS;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void KernelReduceMinMax(const T* input,
|
||||
int64_t numel,
|
||||
T* min_out,
|
||||
T* max_out) {
|
||||
__shared__ T smin[PADDLE_CUDA_NUM_THREADS];
|
||||
__shared__ T smax[PADDLE_CUDA_NUM_THREADS];
|
||||
int tid = threadIdx.x;
|
||||
int64_t global_thread_id =
|
||||
static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
|
||||
int64_t stride = static_cast<int64_t>(gridDim.x) * blockDim.x;
|
||||
|
||||
T local_min = std::numeric_limits<T>::max();
|
||||
T local_max = std::numeric_limits<T>::lowest();
|
||||
|
||||
for (int64_t i = global_thread_id; i < numel; i += stride) {
|
||||
T val = input[i];
|
||||
local_min = min(local_min, val);
|
||||
local_max = max(local_max, val);
|
||||
}
|
||||
|
||||
smin[tid] = local_min;
|
||||
smax[tid] = local_max;
|
||||
__syncthreads();
|
||||
|
||||
for (int offset = blockDim.x / 2; offset > 0; offset >>= 1) {
|
||||
if (tid < offset) {
|
||||
smin[tid] = min(smin[tid], smin[tid + offset]);
|
||||
smax[tid] = max(smax[tid], smax[tid + offset]);
|
||||
}
|
||||
__syncthreads();
|
||||
}
|
||||
|
||||
if (tid == 0) {
|
||||
CudaAtomicMin(min_out, smin[0]);
|
||||
CudaAtomicMax(max_out, smax[0]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename InputT, typename OutT>
|
||||
__global__ void KernelBincount(const InputT* input,
|
||||
const int64_t total_elements,
|
||||
const bool has_weights,
|
||||
const T* weights,
|
||||
OutT* output) {
|
||||
int64_t global_tid =
|
||||
static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
|
||||
int64_t stride = static_cast<int64_t>(gridDim.x) * blockDim.x;
|
||||
for (int64_t i = global_tid; i < total_elements; i += stride) {
|
||||
InputT index = input[i];
|
||||
if (!has_weights) {
|
||||
CudaAtomicAdd(&output[index], 1L);
|
||||
} else {
|
||||
CudaAtomicAdd(&output[index], static_cast<OutT>(weights[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Context, typename T, typename InputT>
|
||||
void BincountCUDAInner(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const optional<DenseTensor>& weights,
|
||||
int64_t minlength,
|
||||
DenseTensor* out) {
|
||||
const DenseTensor* input = &x;
|
||||
DenseTensor* output = out;
|
||||
const InputT* input_data = input->data<InputT>();
|
||||
|
||||
int64_t input_numel = static_cast<int64_t>(input->numel());
|
||||
|
||||
if (input_data == nullptr) {
|
||||
DDim out_dim{minlength};
|
||||
output->Resize(out_dim);
|
||||
Full<int64_t, Context>(dev_ctx, output->dims(), 0, output);
|
||||
return;
|
||||
}
|
||||
|
||||
DenseTensor input_min_max_cpu;
|
||||
input_min_max_cpu.Resize({2});
|
||||
auto* input_min_max_cpu_data =
|
||||
dev_ctx.template HostAlloc<InputT>(&input_min_max_cpu);
|
||||
input_min_max_cpu.data<InputT>()[0] = std::numeric_limits<InputT>::max();
|
||||
input_min_max_cpu.data<InputT>()[1] = std::numeric_limits<InputT>::lowest();
|
||||
|
||||
DenseTensor input_min_max_t;
|
||||
input_min_max_t.Resize({2});
|
||||
auto* input_min_max_data = dev_ctx.template Alloc<InputT>(&input_min_max_t);
|
||||
|
||||
Copy(dev_ctx, input_min_max_cpu, dev_ctx.GetPlace(), true, &input_min_max_t);
|
||||
|
||||
int64_t max_grid_x = dev_ctx.GetCUDAMaxGridDimSize()[0];
|
||||
int64_t num_blocks = std::min(GET_BLOCKS(input_numel), max_grid_x);
|
||||
KernelReduceMinMax<InputT>
|
||||
<<<num_blocks, PADDLE_CUDA_NUM_THREADS, 0, dev_ctx.stream()>>>(
|
||||
input_data, input_numel, input_min_max_data, input_min_max_data + 1);
|
||||
|
||||
Copy(dev_ctx, input_min_max_t, CPUPlace(), true, &input_min_max_cpu);
|
||||
|
||||
InputT input_min = input_min_max_cpu.data<InputT>()[0];
|
||||
|
||||
PADDLE_ENFORCE_GE(
|
||||
input_min,
|
||||
static_cast<InputT>(0),
|
||||
common::errors::InvalidArgument(
|
||||
"The elements in input tensor must be non-negative ints"));
|
||||
|
||||
int64_t output_size =
|
||||
static_cast<int64_t>(input_min_max_cpu.data<InputT>()[1]) + 1L;
|
||||
|
||||
output_size = std::max(output_size, minlength);
|
||||
DDim out_dim{output_size};
|
||||
output->Resize(out_dim);
|
||||
|
||||
bool has_weights = weights.is_initialized();
|
||||
|
||||
const T* weights_data = has_weights ? weights->data<T>() : nullptr;
|
||||
auto stream = dev_ctx.stream();
|
||||
|
||||
if (!has_weights) {
|
||||
int64_t* output_data = dev_ctx.template Alloc<int64_t>(output);
|
||||
funcs::SetConstant<Context, int64_t>()(
|
||||
dev_ctx, output, static_cast<int64_t>(0));
|
||||
|
||||
KernelBincount<T, InputT, int64_t>
|
||||
<<<num_blocks, PADDLE_CUDA_NUM_THREADS, 0, stream>>>(
|
||||
input_data, input_numel, has_weights, weights_data, output_data);
|
||||
} else {
|
||||
if (weights->dtype() == DataType::FLOAT32) {
|
||||
float* output_data = dev_ctx.template Alloc<float>(output);
|
||||
funcs::SetConstant<Context, float>()(
|
||||
dev_ctx, output, static_cast<float>(0));
|
||||
|
||||
KernelBincount<T, InputT, float>
|
||||
<<<num_blocks, PADDLE_CUDA_NUM_THREADS, 0, stream>>>(
|
||||
input_data, input_numel, has_weights, weights_data, output_data);
|
||||
} else {
|
||||
double* output_data = dev_ctx.template Alloc<double>(output);
|
||||
funcs::SetConstant<Context, double>()(
|
||||
dev_ctx, output, static_cast<double>(0));
|
||||
KernelBincount<T, InputT, double>
|
||||
<<<num_blocks, PADDLE_CUDA_NUM_THREADS, 0, stream>>>(
|
||||
input_data, input_numel, has_weights, weights_data, output_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void BincountKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const optional<DenseTensor>& weights,
|
||||
const Scalar& minlength,
|
||||
DenseTensor* out) {
|
||||
int64_t int_minlength = minlength.to<int64_t>();
|
||||
PADDLE_ENFORCE_GE(int_minlength,
|
||||
0,
|
||||
common::errors::InvalidArgument(
|
||||
"The minlength should be greater than or equal to 0."
|
||||
"But received minlength is %d",
|
||||
int_minlength));
|
||||
|
||||
if (x.dtype() == DataType::INT32) {
|
||||
BincountCUDAInner<Context, T, int>(dev_ctx, x, weights, int_minlength, out);
|
||||
} else if (x.dtype() == DataType::INT64) {
|
||||
BincountCUDAInner<Context, T, int64_t>(
|
||||
dev_ctx, x, weights, int_minlength, out);
|
||||
}
|
||||
}
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(bincount,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::BincountKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t) {
|
||||
kernel->OutputAt(0).SetDataType(phi::DataType::UNDEFINED);
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
/* 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. */
|
||||
|
||||
#ifdef __NVCC__
|
||||
#include <curand_kernel.h>
|
||||
#endif
|
||||
#ifdef __HIPCC__
|
||||
#include <hiprand_kernel.h>
|
||||
#endif
|
||||
|
||||
#include "paddle/common/enforce.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_launch_config.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/binomial_kernel.h"
|
||||
#include "paddle/phi/kernels/funcs/for_range.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
__device__ __constant__ float kTailValues[] = {0.0810614667953272,
|
||||
0.0413406959554092,
|
||||
0.0276779256849983,
|
||||
0.02079067210376509,
|
||||
0.0166446911898211,
|
||||
0.0138761288230707,
|
||||
0.0118967099458917,
|
||||
0.0104112652619720,
|
||||
0.00925546218271273,
|
||||
0.00833056343336287};
|
||||
|
||||
template <typename T>
|
||||
__device__ T stirling_approx_tail(int64_t k) {
|
||||
if (k <= 9) {
|
||||
return static_cast<T>(kTailValues[static_cast<size_t>(k)]);
|
||||
}
|
||||
T kp1sq = (k + 1) * (k + 1);
|
||||
return (1.0 / 12 - (1.0 / 360 - 1.0 / 1260 / kp1sq) / kp1sq) / (k + 1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__device__ int64_t btrs(
|
||||
const T n, const T p, int64_t idx, unsigned int seed, unsigned int offset) {
|
||||
int64_t k;
|
||||
T U, V, us;
|
||||
|
||||
#ifdef __NVCC__
|
||||
curandStatePhilox4_32_10_t state;
|
||||
curand_init(seed, idx, offset, &state);
|
||||
#elif __HIPCC__
|
||||
hiprandStatePhilox4_32_10_t state;
|
||||
hiprand_init(seed, idx, offset, &state);
|
||||
#endif
|
||||
|
||||
const T stddev = std::sqrt(n * p * (1 - p));
|
||||
|
||||
const T b = 1.15 + 2.53 * stddev;
|
||||
const T a = -0.0873 + 0.0248 * b + 0.01 * p;
|
||||
const T c = n * p + 0.5;
|
||||
const T v_r = 0.92 - 4.2 / b;
|
||||
const T r = p / (1 - p);
|
||||
|
||||
const T alpha = (2.83 + 5.1 / b) * stddev;
|
||||
const T m = std::floor((n + 1) * p);
|
||||
|
||||
while (1) {
|
||||
#ifdef __NVCC__
|
||||
U = static_cast<T>(curand_uniform(&state)) - 0.5;
|
||||
V = static_cast<T>(curand_uniform(&state));
|
||||
#elif __HIPCC__
|
||||
U = static_cast<T>(hiprand_uniform(&state)) - 0.5;
|
||||
V = static_cast<T>(hiprand_uniform(&state));
|
||||
#endif
|
||||
|
||||
us = 0.5 - std::abs(U);
|
||||
k = static_cast<int64_t>(std::floor((2 * a / us + b) * U + c));
|
||||
|
||||
if (k < 0 || k > n) {
|
||||
continue;
|
||||
}
|
||||
if (us >= 0.07 && V <= v_r) {
|
||||
return k;
|
||||
}
|
||||
|
||||
V = std::log(V * alpha / (a / (us * us) + b));
|
||||
T upperbound =
|
||||
((m + 0.5) * std::log((m + 1) / (r * (n - m + 1))) +
|
||||
(n + 1) * std::log((n - m + 1) / (n - k + 1)) +
|
||||
(k + 0.5) * std::log(r * (n - k + 1) / (k + 1)) +
|
||||
stirling_approx_tail<T>(m) + stirling_approx_tail<T>(n - m) -
|
||||
stirling_approx_tail<T>(k) - stirling_approx_tail<T>(n - k));
|
||||
|
||||
if (V <= upperbound) {
|
||||
return k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__device__ int64_t binomial_inversion(
|
||||
const T n, const T p, int64_t idx, unsigned int seed, unsigned int offset) {
|
||||
T unif;
|
||||
T geom_sum = 0.0;
|
||||
int64_t num_geom = 0;
|
||||
T logprob = std::log1p(-p);
|
||||
|
||||
#ifdef __NVCC__
|
||||
curandStatePhilox4_32_10_t state;
|
||||
curand_init(seed, idx, offset, &state);
|
||||
#elif __HIPCC__
|
||||
hiprandStatePhilox4_32_10_t state;
|
||||
hiprand_init(seed, idx, offset, &state);
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
#ifdef __NVCC__
|
||||
unif = static_cast<T>(curand_uniform(&state));
|
||||
#elif __HIPCC__
|
||||
unif = static_cast<T>(hiprand_uniform(&state));
|
||||
#endif
|
||||
T geom = std::ceil(std::log(unif) / logprob);
|
||||
geom_sum += geom;
|
||||
if (geom_sum > n) {
|
||||
break;
|
||||
}
|
||||
num_geom = num_geom + 1;
|
||||
}
|
||||
return num_geom;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void BinomialSampling(const T* n,
|
||||
const T* p,
|
||||
int64_t* out,
|
||||
const int N,
|
||||
unsigned int seed,
|
||||
unsigned int offset) {
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
CUDA_KERNEL_LOOP_TYPE(idx, N, int64_t) {
|
||||
MT nt = static_cast<MT>(n[idx]);
|
||||
MT pt = static_cast<MT>(p[idx]);
|
||||
if (nt <= 0.0 || pt <= 0.0) {
|
||||
out[idx] = 0;
|
||||
} else if (pt >= 1.0) {
|
||||
out[idx] = static_cast<int64_t>(nt);
|
||||
} else if (pt <= 0.5) {
|
||||
if (nt * pt >= 10.0) {
|
||||
out[idx] = btrs<MT>(nt, pt, idx, seed, offset);
|
||||
} else {
|
||||
out[idx] = binomial_inversion<MT>(nt, pt, idx, seed, offset);
|
||||
}
|
||||
} else {
|
||||
MT qprob = 1.0 - pt;
|
||||
if (nt * qprob >= 10.0) {
|
||||
out[idx] =
|
||||
static_cast<int64_t>(nt) - btrs<MT>(nt, qprob, idx, seed, offset);
|
||||
} else {
|
||||
out[idx] = static_cast<int64_t>(nt) -
|
||||
binomial_inversion<MT>(nt, qprob, idx, seed, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void BinomialKernel(const Context& dev_ctx,
|
||||
const DenseTensor& count,
|
||||
const DenseTensor& prob,
|
||||
DenseTensor* out) {
|
||||
const T* count_data = count.data<T>();
|
||||
const T* prob_data = prob.data<T>();
|
||||
int64_t* out_data = dev_ctx.template Alloc<int64_t>(out);
|
||||
// TODO(large-tensor): downstream functors may still use int; guard until
|
||||
// upgraded.
|
||||
int64_t size = count.numel();
|
||||
|
||||
const int kMaxBlockDim = 256;
|
||||
|
||||
int block_size = std::min(kMaxBlockDim, dev_ctx.GetMaxThreadsPerBlock());
|
||||
dim3 dim_block(block_size);
|
||||
int64_t grid_64 = (size + block_size - 1) / block_size;
|
||||
PADDLE_ENFORCE_LE_UINT32_MAX(grid_64, "binomial grid.x");
|
||||
dim3 dim_grid(static_cast<uint32_t>(grid_64));
|
||||
backends::gpu::LimitGridDim(dev_ctx, &dim_grid);
|
||||
|
||||
auto gen_cuda = dev_ctx.GetGenerator();
|
||||
auto seed_offset = gen_cuda->IncrementOffset(20);
|
||||
uint64_t seed = seed_offset.first;
|
||||
uint64_t offset = seed_offset.second;
|
||||
BinomialSampling<T><<<dim_grid, dim_block>>>(
|
||||
count_data, prob_data, out_data, size, seed, offset);
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(binomial,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::BinomialKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {
|
||||
kernel->OutputAt(0).SetDataType(phi::DataType::INT64);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/bmm_grad_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/bmm_grad_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(bmm_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::BmmGradKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/bmm_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/bmm_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(bmm,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::BmmKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) 2024 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 <algorithm>
|
||||
|
||||
#include "paddle/common/hostdevice.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/core/lod_utils.h"
|
||||
#include "paddle/phi/core/mixed_vector.h"
|
||||
#include "paddle/phi/kernels/funcs/math_function.h"
|
||||
#include "paddle/phi/kernels/gpu/box_clip_kernel.h"
|
||||
#include "paddle/phi/kernels/impl/box_clip_kernel_impl.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
static constexpr int ImInfoSize = 3;
|
||||
|
||||
template <typename T, int BlockSize>
|
||||
static __global__ void GPUBoxClip(const T *input,
|
||||
const size_t *lod,
|
||||
const size_t width,
|
||||
const T *im_info,
|
||||
T *output) {
|
||||
T im_w = round(im_info[blockIdx.x * ImInfoSize + 1] /
|
||||
im_info[blockIdx.x * ImInfoSize + 2]);
|
||||
T im_h = round(im_info[blockIdx.x * ImInfoSize] /
|
||||
im_info[blockIdx.x * ImInfoSize + 2]);
|
||||
for (size_t i = threadIdx.x;
|
||||
i < (lod[blockIdx.x + 1] - lod[blockIdx.x]) * width;
|
||||
i += BlockSize) {
|
||||
size_t idx = lod[blockIdx.x] * width + i;
|
||||
T im_size = (idx % 2 == 0) ? im_w : im_h;
|
||||
output[idx] = max(min(input[idx], im_size - 1), T(0.));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void GPUBoxClipKernel(const Context &dev_ctx,
|
||||
const DenseTensor &input,
|
||||
const DenseTensor &im_info,
|
||||
DenseTensor *output) {
|
||||
auto *input_p = &input;
|
||||
auto *im_info_p = &im_info;
|
||||
|
||||
const int64_t num = input_p->dims()[0];
|
||||
const int64_t bbox_width = input_p->numel() / num;
|
||||
auto lod = input_p->lod();
|
||||
LegacyLoD abs_offset_lod = ToAbsOffset(lod);
|
||||
|
||||
auto stream = dev_ctx.stream();
|
||||
const size_t batch_size = lod.back().size() - 1;
|
||||
T *output_data = dev_ctx.template Alloc<T>(output);
|
||||
MixVector<size_t> mix_vector(&abs_offset_lod[0]);
|
||||
GPUBoxClip<T, 512><<<batch_size, 512, 0, stream>>>(
|
||||
input_p->data<T>(),
|
||||
mix_vector.CUDAMutableData(dev_ctx.GetPlace()),
|
||||
bbox_width,
|
||||
im_info_p->data<T>(),
|
||||
output_data);
|
||||
mix_vector.CopyToCPU();
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(
|
||||
box_clip, GPU, ALL_LAYOUT, phi::GPUBoxClipKernel, float, double) {}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void GPUBoxClipKernel(const Context &dev_ctx,
|
||||
const DenseTensor &input,
|
||||
const DenseTensor &im_info,
|
||||
DenseTensor *output);
|
||||
} // namespace phi
|
||||
@@ -0,0 +1,264 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/box_coder_kernel.h"
|
||||
|
||||
#include <thrust/device_vector.h>
|
||||
#include <thrust/host_vector.h>
|
||||
|
||||
#include "paddle/phi/backends/gpu/cuda/cuda_graph_with_memory_pool.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/common/memory_utils.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/full_kernel.h"
|
||||
#include "paddle/phi/kernels/impl/box_coder.h"
|
||||
namespace phi {
|
||||
|
||||
template <typename T>
|
||||
__global__ void EncodeCenterSizeKernel(const T *prior_box_data,
|
||||
const T *prior_box_var_data,
|
||||
const T *target_box_data,
|
||||
const int64_t row,
|
||||
const int64_t col,
|
||||
const int64_t len,
|
||||
const bool normalized,
|
||||
const T prior_box_var_size,
|
||||
const float *variance,
|
||||
const int64_t var_size,
|
||||
T *output) {
|
||||
const int64_t idx =
|
||||
threadIdx.x + static_cast<int64_t>(blockIdx.x) * blockDim.x;
|
||||
if (idx < row * col) {
|
||||
const int64_t row_idx = idx / col;
|
||||
const int64_t col_idx = idx % col;
|
||||
T prior_box_width = prior_box_data[col_idx * len + 2] -
|
||||
prior_box_data[col_idx * len] + (normalized == false);
|
||||
T prior_box_height = prior_box_data[col_idx * len + 3] -
|
||||
prior_box_data[col_idx * len + 1] +
|
||||
(normalized == false);
|
||||
T prior_box_center_x = prior_box_data[col_idx * len] + prior_box_width / 2;
|
||||
T prior_box_center_y =
|
||||
prior_box_data[col_idx * len + 1] + prior_box_height / 2;
|
||||
|
||||
T target_box_center_x =
|
||||
(target_box_data[row_idx * len + 2] + target_box_data[row_idx * len]) /
|
||||
2;
|
||||
T target_box_center_y = (target_box_data[row_idx * len + 3] +
|
||||
target_box_data[row_idx * len + 1]) /
|
||||
2;
|
||||
T target_box_width = target_box_data[row_idx * len + 2] -
|
||||
target_box_data[row_idx * len] + (normalized == false);
|
||||
T target_box_height = target_box_data[row_idx * len + 3] -
|
||||
target_box_data[row_idx * len + 1] +
|
||||
(normalized == false);
|
||||
|
||||
output[idx * len] =
|
||||
(target_box_center_x - prior_box_center_x) / prior_box_width;
|
||||
output[idx * len + 1] =
|
||||
(target_box_center_y - prior_box_center_y) / prior_box_height;
|
||||
output[idx * len + 2] = log(fabs(target_box_width / prior_box_width));
|
||||
output[idx * len + 3] = log(fabs(target_box_height / prior_box_height));
|
||||
if (prior_box_var_data) {
|
||||
int64_t prior_var_offset = col_idx * len;
|
||||
output[idx * len] /= prior_box_var_data[prior_var_offset];
|
||||
output[idx * len + 1] /= prior_box_var_data[prior_var_offset + 1];
|
||||
output[idx * len + 2] /= prior_box_var_data[prior_var_offset + 2];
|
||||
output[idx * len + 3] /= prior_box_var_data[prior_var_offset + 3];
|
||||
} else if (var_size == 4) {
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
output[idx * len + k] /= static_cast<T>(variance[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void DecodeCenterSizeKernel(const T *prior_box_data,
|
||||
const T *prior_box_var_data,
|
||||
const T *target_box_data,
|
||||
const int64_t row,
|
||||
const int64_t col,
|
||||
const int64_t len,
|
||||
const bool normalized,
|
||||
const T prior_box_var_size,
|
||||
const float *variance,
|
||||
const int64_t var_size,
|
||||
const int axis,
|
||||
T *output) {
|
||||
const int64_t idx =
|
||||
threadIdx.x + static_cast<int64_t>(blockIdx.x) * blockDim.x;
|
||||
int64_t prior_box_offset = 0;
|
||||
if (idx < row * col) {
|
||||
const int64_t col_idx = idx % col;
|
||||
const int64_t row_idx = idx / col;
|
||||
prior_box_offset = axis == 0 ? col_idx * len : row_idx * len;
|
||||
T prior_box_width = prior_box_data[prior_box_offset + 2] -
|
||||
prior_box_data[prior_box_offset] +
|
||||
(normalized == false);
|
||||
T prior_box_height = prior_box_data[prior_box_offset + 3] -
|
||||
prior_box_data[prior_box_offset + 1] +
|
||||
(normalized == false);
|
||||
T prior_box_center_x =
|
||||
prior_box_data[prior_box_offset] + prior_box_width / 2;
|
||||
T prior_box_center_y =
|
||||
prior_box_data[prior_box_offset + 1] + prior_box_height / 2;
|
||||
T target_box_width, target_box_height;
|
||||
T target_box_center_x, target_box_center_y;
|
||||
T box_var_x = T(1), box_var_y = T(1);
|
||||
T box_var_w = T(1), box_var_h = T(1);
|
||||
if (prior_box_var_data) {
|
||||
int64_t prior_var_offset = axis == 0 ? col_idx * len : row_idx * len;
|
||||
box_var_x = prior_box_var_data[prior_var_offset];
|
||||
box_var_y = prior_box_var_data[prior_var_offset + 1];
|
||||
box_var_w = prior_box_var_data[prior_var_offset + 2];
|
||||
box_var_h = prior_box_var_data[prior_var_offset + 3];
|
||||
} else if (var_size == 4) {
|
||||
box_var_x = static_cast<T>(variance[0]);
|
||||
box_var_y = static_cast<T>(variance[1]);
|
||||
box_var_w = static_cast<T>(variance[2]);
|
||||
box_var_h = static_cast<T>(variance[3]);
|
||||
}
|
||||
target_box_width =
|
||||
exp(box_var_w * target_box_data[idx * len + 2]) * prior_box_width;
|
||||
target_box_height =
|
||||
exp(box_var_h * target_box_data[idx * len + 3]) * prior_box_height;
|
||||
target_box_center_x =
|
||||
box_var_x * target_box_data[idx * len] * prior_box_width +
|
||||
prior_box_center_x;
|
||||
target_box_center_y =
|
||||
box_var_y * target_box_data[idx * len + 1] * prior_box_height +
|
||||
prior_box_center_y;
|
||||
|
||||
output[idx * len] = target_box_center_x - target_box_width / 2;
|
||||
output[idx * len + 1] = target_box_center_y - target_box_height / 2;
|
||||
output[idx * len + 2] =
|
||||
target_box_center_x + target_box_width / 2 - (normalized == false);
|
||||
output[idx * len + 3] =
|
||||
target_box_center_y + target_box_height / 2 - (normalized == false);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void BoxCoderKernel(const Context &dev_ctx,
|
||||
const DenseTensor &prior_box,
|
||||
const optional<DenseTensor> &prior_box_var,
|
||||
const DenseTensor &target_box,
|
||||
const std::string &code_type_str,
|
||||
bool normalized,
|
||||
int axis,
|
||||
const std::vector<float> &variance,
|
||||
DenseTensor *output_box) {
|
||||
// prior_box and prior_box_var have the same shape, so do not judge
|
||||
// prior_box_var
|
||||
if (prior_box.numel() == 0 || target_box.numel() == 0) {
|
||||
Full<T, Context>(dev_ctx, output_box->dims(), 0, output_box);
|
||||
return;
|
||||
}
|
||||
|
||||
const T *prior_box_data = prior_box.template data<T>();
|
||||
const T *target_box_data = target_box.template data<T>();
|
||||
const T *prior_box_var_data = nullptr;
|
||||
auto prior_box_var_size = 0;
|
||||
if (prior_box_var) {
|
||||
PADDLE_ENFORCE_EQ(variance.empty(),
|
||||
true,
|
||||
common::errors::InvalidArgument(
|
||||
"Input 'PriorBoxVar' and attribute 'variance'"
|
||||
" of BoxCoder operator should not be used at the "
|
||||
"same time."));
|
||||
prior_box_var_data = prior_box_var->data<T>();
|
||||
prior_box_var_size = prior_box_var->dims().size();
|
||||
}
|
||||
if (!(variance.empty())) {
|
||||
PADDLE_ENFORCE_EQ(static_cast<int>(variance.size()),
|
||||
4,
|
||||
common::errors::InvalidArgument(
|
||||
"Size of attribute 'variance' in BoxCoder operator"
|
||||
" should be 4. But received size is %d",
|
||||
variance.size()));
|
||||
}
|
||||
|
||||
if (target_box.lod().size()) {
|
||||
PADDLE_ENFORCE_EQ(target_box.lod().size(),
|
||||
1,
|
||||
common::errors::InvalidArgument(
|
||||
"Input 'TargetBox' of BoxCoder operator only"
|
||||
" supports LoD with one level."));
|
||||
}
|
||||
const int var_size = static_cast<int>(variance.size());
|
||||
auto code_type = funcs::GetBoxCodeType(code_type_str);
|
||||
int64_t row = target_box.dims()[0];
|
||||
int64_t col = prior_box.dims()[0];
|
||||
if (code_type == funcs::BoxCodeType::kDecodeCenterSize) {
|
||||
col = target_box.dims()[1];
|
||||
}
|
||||
int64_t len = prior_box.dims()[1];
|
||||
int block = 512;
|
||||
int64_t grid64 = (row * col + block - 1) / block;
|
||||
PADDLE_ENFORCE_LE_INT_MAX(grid64, "grid");
|
||||
int grid = static_cast<int>(grid64);
|
||||
|
||||
int64_t bytes = var_size * sizeof(float);
|
||||
auto dev_var =
|
||||
memory_utils::Alloc(dev_ctx.GetPlace(),
|
||||
bytes,
|
||||
Stream(reinterpret_cast<StreamId>(dev_ctx.stream())));
|
||||
float *dev_var_data = reinterpret_cast<float *>(dev_var->ptr());
|
||||
auto cplace = CPUPlace();
|
||||
const auto gplace = dev_ctx.GetPlace();
|
||||
const float *stable_variance =
|
||||
backends::gpu::RestoreHostMemIfCapturingCUDAGraph(
|
||||
const_cast<float *>(variance.data()), variance.size());
|
||||
memory_utils::Copy(
|
||||
gplace, dev_var_data, cplace, stable_variance, bytes, dev_ctx.stream());
|
||||
|
||||
output_box->Resize({row, col, len});
|
||||
dev_ctx.template Alloc<T>(output_box);
|
||||
T *output = output_box->data<T>();
|
||||
|
||||
if (code_type == funcs::BoxCodeType::kEncodeCenterSize) {
|
||||
EncodeCenterSizeKernel<T>
|
||||
<<<grid, block, 0, dev_ctx.stream()>>>(prior_box_data,
|
||||
prior_box_var_data,
|
||||
target_box_data,
|
||||
row,
|
||||
col,
|
||||
len,
|
||||
normalized,
|
||||
prior_box_var_size,
|
||||
dev_var_data,
|
||||
var_size,
|
||||
output);
|
||||
} else if (code_type == funcs::BoxCodeType::kDecodeCenterSize) {
|
||||
DecodeCenterSizeKernel<T>
|
||||
<<<grid, block, 0, dev_ctx.stream()>>>(prior_box_data,
|
||||
prior_box_var_data,
|
||||
target_box_data,
|
||||
row,
|
||||
col,
|
||||
len,
|
||||
normalized,
|
||||
prior_box_var_size,
|
||||
dev_var_data,
|
||||
var_size,
|
||||
axis,
|
||||
output);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(
|
||||
box_coder, GPU, ALL_LAYOUT, phi::BoxCoderKernel, float, double) {}
|
||||
@@ -0,0 +1,89 @@
|
||||
// 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/broadcast_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/all_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
#include "paddle/phi/core/distributed/nccl_comm_context.h"
|
||||
#endif
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void BroadcastKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
int root,
|
||||
DenseTensor* out) {
|
||||
PADDLE_ENFORCE_GT(x.numel(),
|
||||
0,
|
||||
common::errors::InvalidArgument(
|
||||
"Tensor need be broadcast must not empty."));
|
||||
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
dev_ctx.template Alloc<T>(out);
|
||||
gpuStream_t stream = dev_ctx.stream();
|
||||
auto comm_context =
|
||||
static_cast<distributed::NCCLCommContext*>(dev_ctx.GetCommContext());
|
||||
PADDLE_ENFORCE_NE(
|
||||
comm_context,
|
||||
nullptr,
|
||||
errors::Unavailable("NCCLCommContext is nullptr, collective op should "
|
||||
"has ring_id attr."));
|
||||
comm_context->Broadcast(out, x, root, stream);
|
||||
out->set_lod(x.lod());
|
||||
#else
|
||||
PADDLE_THROW(
|
||||
errors::PreconditionNotMet("PaddlePaddle should compile with GPU."));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
#if NCCL_VERSION_CODE >= 21000
|
||||
PD_REGISTER_KERNEL(broadcast,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::BroadcastKernel,
|
||||
float,
|
||||
double,
|
||||
phi::bfloat16,
|
||||
int,
|
||||
bool,
|
||||
int8_t,
|
||||
uint8_t,
|
||||
int16_t,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
#else
|
||||
PD_REGISTER_KERNEL(broadcast,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::BroadcastKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
bool,
|
||||
int8_t,
|
||||
uint8_t,
|
||||
int16_t,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
#endif
|
||||
@@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/broadcast_tensors_grad_kernel.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/phi/core/enforce.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/reduce_function.h"
|
||||
#include "paddle/phi/kernels/primitive/functor_primitives.h"
|
||||
#include "paddle/phi/kernels/reduce_sum_kernel.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void BroadcastTensorsGradKernel(const Context& dev_ctx,
|
||||
const std::vector<const DenseTensor*>& inputs,
|
||||
const std::vector<const DenseTensor*>& dout,
|
||||
std::vector<DenseTensor*> dx) {
|
||||
(void)inputs;
|
||||
// Find reduce dimensions
|
||||
const auto& in_tensors = dout;
|
||||
auto& out_tensors = dx;
|
||||
|
||||
size_t num_ins = in_tensors.size();
|
||||
|
||||
PADDLE_ENFORCE_GT(
|
||||
num_ins,
|
||||
1,
|
||||
errors::InvalidArgument(
|
||||
"Expected at least 2 input tensors, but only received %d.",
|
||||
in_tensors.size()));
|
||||
|
||||
PADDLE_ENFORCE_EQ(
|
||||
num_ins,
|
||||
out_tensors.size(),
|
||||
errors::InvalidArgument(
|
||||
"BroadcastTensorsOp expects equal number of inputs and outputs,"
|
||||
"but received: %d inputs v.s %d outputs",
|
||||
num_ins,
|
||||
out_tensors.size()));
|
||||
|
||||
// For each In-Out tensor pair,
|
||||
// Prepare and apply broadcast dims array
|
||||
for (size_t i = 0; i < num_ins; i++) {
|
||||
auto* input_tensor = in_tensors[i];
|
||||
auto* output_tensor = out_tensors[i];
|
||||
|
||||
const DDim& input_dims = input_tensor->dims();
|
||||
const DDim& output_dims = output_tensor->dims();
|
||||
|
||||
int in_rank = input_dims.size();
|
||||
int out_rank = output_dims.size();
|
||||
|
||||
// Collect reduce_dims
|
||||
// Example:
|
||||
// dX = [1,1,1,1]
|
||||
// dOut = [1,1,1,4]
|
||||
//
|
||||
// reduce_dims = [3] // reduce along the broadcasted axis
|
||||
std::vector<int> reduce_dims_vec;
|
||||
for (int j = 0; j < in_rank; j++) {
|
||||
int out_axis = out_rank - j - 1;
|
||||
int in_axis = in_rank - j - 1;
|
||||
|
||||
if (out_axis < 0 || output_dims[out_axis] != input_dims[in_axis]) {
|
||||
reduce_dims_vec.push_back(in_axis);
|
||||
}
|
||||
}
|
||||
|
||||
bool just_copy = (reduce_dims_vec.size() == 0);
|
||||
dev_ctx.template Alloc<T>(output_tensor);
|
||||
if (just_copy) {
|
||||
// Turns out to be a No-Op, simply copy tensors
|
||||
Copy(dev_ctx, *input_tensor, dev_ctx.GetPlace(), false, output_tensor);
|
||||
} else {
|
||||
// reduce_sum implementation on CUDA
|
||||
SumKernel<T, Context>(dev_ctx,
|
||||
*input_tensor,
|
||||
reduce_dims_vec,
|
||||
output_tensor->dtype(),
|
||||
false,
|
||||
output_tensor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(broadcast_tensors_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::BroadcastTensorsGradKernel,
|
||||
bool,
|
||||
int,
|
||||
int64_t,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/broadcast_tensors_kernel.h"
|
||||
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/broadcast_tensors_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(broadcast_tensors,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::BroadcastTensorsKernel,
|
||||
bool,
|
||||
int,
|
||||
int64_t,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
@@ -0,0 +1,124 @@
|
||||
// Copyright (c) 2024 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/api/include/tensor.h"
|
||||
#include "paddle/phi/backends/context_pool.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/c_concat_kernel.h"
|
||||
#include "paddle/phi/kernels/funcs/concat_and_split_functor.h"
|
||||
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
#include "paddle/phi/core/distributed/nccl_comm_context.h"
|
||||
#endif
|
||||
#if defined(PADDLE_WITH_FLAGCX)
|
||||
#include "paddle/phi/core/distributed/flagcx_comm_context.h"
|
||||
#endif
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void CConcatKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x_in,
|
||||
int rank,
|
||||
int nranks,
|
||||
int ring_id UNUSED,
|
||||
bool use_calc_stream UNUSED,
|
||||
bool use_model_parallel UNUSED,
|
||||
DenseTensor* out) {
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
auto x = &x_in;
|
||||
PADDLE_ENFORCE_GE(rank,
|
||||
0,
|
||||
common::errors::PreconditionNotMet(
|
||||
"The value of rank (%d) for c_concat must be "
|
||||
"greater than or equal to 0.",
|
||||
rank));
|
||||
PADDLE_ENFORCE_GE(nranks,
|
||||
2,
|
||||
common::errors::PreconditionNotMet(
|
||||
"The value of nranks (%d) for c_concat must be "
|
||||
"greater than or equal to 2.",
|
||||
nranks));
|
||||
PADDLE_ENFORCE_LT(rank,
|
||||
nranks,
|
||||
common::errors::PreconditionNotMet(
|
||||
"The value of rank (%d) for c_concat must be "
|
||||
"less than that of nranks (%d).",
|
||||
rank,
|
||||
nranks));
|
||||
|
||||
DenseTensor temp_out;
|
||||
DDim temp_out_dims = x->dims();
|
||||
temp_out_dims[0] *= nranks;
|
||||
temp_out.Resize(temp_out_dims);
|
||||
dev_ctx.template Alloc<T>(&temp_out);
|
||||
|
||||
gpuStream_t stream = nullptr;
|
||||
|
||||
#if defined(PADDLE_WITH_FLAGCX) && defined(PADDLE_KERNEL_WITH_FLAGCX)
|
||||
distributed::FlagcxCommContext* comm_ctx = nullptr;
|
||||
comm_ctx =
|
||||
static_cast<distributed::FlagcxCommContext*>(dev_ctx.GetCommContext());
|
||||
#else
|
||||
distributed::NCCLCommContext* comm_ctx = nullptr;
|
||||
comm_ctx =
|
||||
static_cast<distributed::NCCLCommContext*>(dev_ctx.GetCommContext());
|
||||
#endif
|
||||
PADDLE_ENFORCE_NE(comm_ctx,
|
||||
nullptr,
|
||||
common::errors::Unavailable(
|
||||
"NCCLCommContext is nullptr, collective op should "
|
||||
"has ring_id attr."));
|
||||
stream = dev_ctx.stream();
|
||||
#if defined(PADDLE_WITH_FLAGCX) && defined(PADDLE_KERNEL_WITH_FLAGCX)
|
||||
comm_ctx->AllGather(&temp_out, *x, reinterpret_cast<flagcxStream_t>(&stream));
|
||||
#else
|
||||
comm_ctx->AllGather(&temp_out, *x, stream);
|
||||
#endif
|
||||
|
||||
std::vector<DenseTensor> inputs;
|
||||
int axis = x->dims().size() - 1;
|
||||
auto out_dims = x->dims();
|
||||
out_dims[out_dims.size() - 1] *= nranks;
|
||||
int64_t rows_per_tensor = x->dims()[0];
|
||||
int64_t offset = 0;
|
||||
for (int i = 0; i < nranks; i++) {
|
||||
DenseTensor temp = temp_out.Slice(offset, offset + rows_per_tensor);
|
||||
inputs.emplace_back(temp);
|
||||
offset += rows_per_tensor;
|
||||
}
|
||||
|
||||
funcs::ConcatFunctor<GPUContext, T> functor;
|
||||
out->Resize(out_dims);
|
||||
dev_ctx.template Alloc<T>(out);
|
||||
functor(dev_ctx, inputs, axis, out);
|
||||
#else
|
||||
PADDLE_THROW(common::errors::PreconditionNotMet(
|
||||
"PaddlePaddle should compile with GPU."));
|
||||
#endif
|
||||
}
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(c_concat,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CConcatKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::bfloat16,
|
||||
phi::float16) {}
|
||||
@@ -0,0 +1,152 @@
|
||||
// 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/c_embedding_kernel.h"
|
||||
|
||||
#include "glog/logging.h"
|
||||
|
||||
#include "paddle/common/flags.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/eigen/common.h"
|
||||
#include "paddle/phi/kernels/funcs/embedding_grad.h"
|
||||
|
||||
COMMON_DECLARE_int64(embedding_deterministic);
|
||||
|
||||
namespace phi {
|
||||
|
||||
static constexpr int kNumCUDAThreads = 512;
|
||||
static constexpr int kNumMaximumNumBlocks = 4096;
|
||||
|
||||
static inline int NumBlocks(const int64_t N) {
|
||||
return static_cast<int>(std::min<int64_t>(
|
||||
(N + kNumCUDAThreads - 1) / kNumCUDAThreads, kNumMaximumNumBlocks));
|
||||
}
|
||||
|
||||
template <typename T, typename IndexT>
|
||||
__global__ void CEmbeddingGrad(T* table,
|
||||
const T* output,
|
||||
const IndexT* ids,
|
||||
const int64_t rows,
|
||||
const int64_t columns,
|
||||
const int64_t N,
|
||||
const int64_t start_idx,
|
||||
const int64_t end_idx,
|
||||
const int64_t limit) {
|
||||
CUDA_KERNEL_LOOP_TYPE(i, limit, int64_t) {
|
||||
int64_t row = i / columns;
|
||||
int64_t col = i % columns;
|
||||
auto id = ids[row];
|
||||
if (id >= start_idx && id < end_idx) {
|
||||
auto real_idx = id - start_idx;
|
||||
CudaAtomicAdd(&table[real_idx * columns + col], output[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void CEmbeddingGradKernel(const Context& dev_ctx,
|
||||
const DenseTensor& w,
|
||||
const DenseTensor& ids,
|
||||
const DenseTensor& out_grad,
|
||||
int64_t start_index,
|
||||
DenseTensor* w_grad) {
|
||||
int64_t N = w_grad->dims()[0];
|
||||
int64_t D = w_grad->dims()[1];
|
||||
int64_t K = ids.numel();
|
||||
|
||||
auto limit = K * D;
|
||||
auto blocks = NumBlocks(limit);
|
||||
int threads = kNumCUDAThreads;
|
||||
|
||||
const T* d_output = out_grad.data<T>();
|
||||
T* d_table = dev_ctx.template Alloc<T>(w_grad);
|
||||
|
||||
auto t = EigenVector<T>::Flatten(*w_grad);
|
||||
t.device(*dev_ctx.eigen_device()) = t.constant(static_cast<T>(0));
|
||||
|
||||
const auto& index_type = ids.dtype();
|
||||
if (FLAGS_embedding_deterministic == 1) {
|
||||
if (index_type == DataType::INT32) {
|
||||
funcs::LaunchEmbeddingGradDeterministicKernel<T, int32_t>(
|
||||
dev_ctx,
|
||||
ids.data<int32_t>(),
|
||||
d_output,
|
||||
d_table,
|
||||
N,
|
||||
D,
|
||||
K,
|
||||
start_index);
|
||||
return;
|
||||
} else if (index_type == DataType::INT64) {
|
||||
funcs::LaunchEmbeddingGradDeterministicKernel<T, int64_t>(
|
||||
dev_ctx,
|
||||
ids.data<int64_t>(),
|
||||
d_output,
|
||||
d_table,
|
||||
N,
|
||||
D,
|
||||
K,
|
||||
start_index);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (FLAGS_embedding_deterministic > 1) {
|
||||
VLOG(2) << "Run grad kernel of embedding with single thread.";
|
||||
blocks = 1;
|
||||
}
|
||||
const int64_t end_idx = start_index + N;
|
||||
if (index_type == DataType::INT32) {
|
||||
CEmbeddingGrad<T, int32_t>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(d_table,
|
||||
d_output,
|
||||
ids.data<int32_t>(),
|
||||
K,
|
||||
D,
|
||||
N,
|
||||
start_index,
|
||||
end_idx,
|
||||
limit);
|
||||
return;
|
||||
} else if (index_type == DataType::INT64) {
|
||||
CEmbeddingGrad<T, int64_t>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(d_table,
|
||||
d_output,
|
||||
ids.data<int64_t>(),
|
||||
K,
|
||||
D,
|
||||
N,
|
||||
start_index,
|
||||
end_idx,
|
||||
limit);
|
||||
return;
|
||||
}
|
||||
}
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"The data type of Input(Ids) must be int32 or int64."));
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(c_embedding_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CEmbeddingGradKernel,
|
||||
float,
|
||||
double,
|
||||
phi::bfloat16,
|
||||
phi::float16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
@@ -0,0 +1,125 @@
|
||||
// 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/c_embedding_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
static constexpr int kNumCUDAThreads = 512;
|
||||
static constexpr int kNumMaximumNumBlocks = 4096;
|
||||
|
||||
static inline int NumBlocks(const int64_t N) {
|
||||
return static_cast<int>(std::min<int64_t>(
|
||||
(N + kNumCUDAThreads - 1) / kNumCUDAThreads, kNumMaximumNumBlocks));
|
||||
}
|
||||
|
||||
template <typename T, typename IndexT>
|
||||
__global__ void CEmbedding(T* out,
|
||||
const T* table,
|
||||
const IndexT* ids,
|
||||
const int64_t rows,
|
||||
const int64_t columns,
|
||||
const int64_t N,
|
||||
const int64_t start_idx,
|
||||
const int64_t end_idx,
|
||||
const int64_t limit,
|
||||
const int64_t vocab_size) {
|
||||
CUDA_KERNEL_LOOP_TYPE(i, limit, int64_t) {
|
||||
int64_t row = i / columns;
|
||||
int64_t col = i % columns;
|
||||
auto id = ids[row];
|
||||
|
||||
PADDLE_ENFORCE(
|
||||
id >= 0 && (vocab_size < 0 || id < vocab_size),
|
||||
"The index is out of bounds, "
|
||||
"please check whether the dimensions of index and "
|
||||
"input meet the requirements. It should "
|
||||
"be less than [%d] and greater than or equal to 0, but received [%d]",
|
||||
vocab_size,
|
||||
id);
|
||||
if (id >= start_idx && id < end_idx) {
|
||||
auto real_idx = id - start_idx;
|
||||
out[i] = table[real_idx * columns + col];
|
||||
} else {
|
||||
out[i] = static_cast<T>(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void CEmbeddingKernel(const Context& dev_ctx,
|
||||
const DenseTensor& w,
|
||||
const DenseTensor& ids,
|
||||
int64_t start_index,
|
||||
int64_t vocab_size,
|
||||
DenseTensor* out) {
|
||||
int64_t N = w.dims()[0];
|
||||
int64_t D = w.dims()[1];
|
||||
int64_t K = ids.numel();
|
||||
|
||||
const int64_t end_idx = start_index + N;
|
||||
|
||||
auto* table = w.data<T>();
|
||||
auto* output = dev_ctx.template Alloc<T>(out);
|
||||
|
||||
auto limit = K * D;
|
||||
auto blocks = NumBlocks(limit);
|
||||
int threads = kNumCUDAThreads;
|
||||
|
||||
const auto& index_type = ids.dtype();
|
||||
if (index_type == DataType::INT32) {
|
||||
CEmbedding<T, int32_t>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(output,
|
||||
table,
|
||||
ids.data<int32_t>(),
|
||||
K,
|
||||
D,
|
||||
N,
|
||||
start_index,
|
||||
end_idx,
|
||||
limit,
|
||||
vocab_size);
|
||||
|
||||
} else if (index_type == DataType::INT64) {
|
||||
CEmbedding<T, int64_t>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(output,
|
||||
table,
|
||||
ids.data<int64_t>(),
|
||||
K,
|
||||
D,
|
||||
N,
|
||||
start_index,
|
||||
end_idx,
|
||||
limit,
|
||||
vocab_size);
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::Unavailable(
|
||||
"GPU c_embedding ids only support int32 or int64."));
|
||||
}
|
||||
}
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(c_embedding,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CEmbeddingKernel,
|
||||
float,
|
||||
double,
|
||||
phi::bfloat16,
|
||||
phi::float16,
|
||||
phi::complex64,
|
||||
phi::complex128) {}
|
||||
@@ -0,0 +1,30 @@
|
||||
/* 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/c_identity_kernel.h"
|
||||
#include "paddle/phi/kernels/impl/c_identity_kernel_impl.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
PD_REGISTER_KERNEL(c_identity,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CIdentityKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::bfloat16,
|
||||
phi::float16) {}
|
||||
@@ -0,0 +1,125 @@
|
||||
// Copyright (c) 2024 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/gpu/c_scatter_kernel.h"
|
||||
#include "glog/logging.h"
|
||||
#include "paddle/phi/core/distributed/comm_context_manager.h"
|
||||
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
#include "paddle/phi/core/distributed/nccl_comm_context.h"
|
||||
#endif
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void CScatterOpCUDAKernel(const Context& dev_ctx,
|
||||
const DenseTensor& input,
|
||||
int ring_id,
|
||||
int root,
|
||||
int nranks,
|
||||
bool use_calc_stream,
|
||||
DenseTensor* out) {
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
auto x = &input;
|
||||
int64_t numel = x->numel();
|
||||
ncclDataType_t dtype = ToNCCLDataType(x->dtype());
|
||||
|
||||
int root_id = root;
|
||||
auto place = dev_ctx.GetPlace();
|
||||
gpuStream_t stream = nullptr;
|
||||
distributed::NCCLCommContext* comm_ctx = nullptr;
|
||||
PADDLE_ENFORCE_GE(
|
||||
root_id,
|
||||
0,
|
||||
common::errors::InvalidArgument(
|
||||
"The root_id (%d) for c_scatter_op must be non-negative.", root_id));
|
||||
PADDLE_ENFORCE_GE(
|
||||
ring_id,
|
||||
0,
|
||||
common::errors::InvalidArgument(
|
||||
"The ring_id (%d) for c_scatter_op must be non-negative.", ring_id));
|
||||
|
||||
comm_ctx =
|
||||
static_cast<distributed::NCCLCommContext*>(dev_ctx.GetCommContext());
|
||||
PADDLE_ENFORCE_NE(comm_ctx,
|
||||
nullptr,
|
||||
common::errors::Unavailable(
|
||||
"NCCLCommContext is nullptr, collective op should "
|
||||
"has ring_id attr."));
|
||||
PADDLE_ENFORCE_EQ(nranks,
|
||||
comm_ctx->GetSize(),
|
||||
common::errors::InvalidArgument(
|
||||
"The number of ranks (%d) you set of must "
|
||||
"be equal to comm_ctx->GetSize() (%d).",
|
||||
nranks,
|
||||
comm_ctx->GetSize()));
|
||||
|
||||
stream = comm_ctx->GetStream();
|
||||
VLOG(3) << "new comm_context_manager has ring_id " << ring_id;
|
||||
|
||||
if (use_calc_stream) {
|
||||
// should ExecutionContext for calc stream.
|
||||
stream = dev_ctx.stream();
|
||||
}
|
||||
|
||||
DDim x_dims = x->dims();
|
||||
DDim out_dims(x_dims);
|
||||
DenseTensor temp;
|
||||
temp.Resize(out_dims);
|
||||
auto out_ptr = dev_ctx.template Alloc<T>(&temp);
|
||||
|
||||
if (root_id == comm_ctx->GetRank()) {
|
||||
comm_ctx->Broadcast(const_cast<DenseTensor*>(x), *x, root_id, stream);
|
||||
Copy(dev_ctx,
|
||||
*static_cast<const DenseTensor*>(x),
|
||||
place,
|
||||
false,
|
||||
static_cast<DenseTensor*>(&temp));
|
||||
} else {
|
||||
comm_ctx->Broadcast(&temp, temp, root_id, stream);
|
||||
}
|
||||
|
||||
out_dims[0] = out_dims[0] / nranks;
|
||||
auto start_index = out_dims[0] * comm_ctx->GetRank();
|
||||
auto end_index = start_index + out_dims[0];
|
||||
temp = temp.Slice(start_index, end_index);
|
||||
temp.Resize(out_dims);
|
||||
out->Resize(out_dims);
|
||||
dev_ctx.template Alloc<T>(out);
|
||||
Copy(dev_ctx,
|
||||
*static_cast<const DenseTensor*>(&temp),
|
||||
place,
|
||||
true,
|
||||
static_cast<DenseTensor*>(out));
|
||||
out->Resize(out_dims);
|
||||
#else
|
||||
PADDLE_ENFORCE_EQ(
|
||||
true,
|
||||
false,
|
||||
common::errors::Unavailable("PaddlePaddle should compile with GPU."));
|
||||
#endif
|
||||
}
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(c_scatter,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CScatterOpCUDAKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16) {}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void CScatterOpCUDAKernel(const Context& dev_ctx,
|
||||
const DenseTensor& input,
|
||||
int ring_id,
|
||||
int root,
|
||||
int nranks,
|
||||
bool use_calc_stream,
|
||||
DenseTensor* out);
|
||||
} // namespace phi
|
||||
@@ -0,0 +1,229 @@
|
||||
// Copyright (c) 2024 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/c_softmax_with_cross_entropy_grad_kernel.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/axis_utils.h"
|
||||
#include "paddle/phi/kernels/funcs/cross_entropy.h"
|
||||
#include "paddle/phi/kernels/funcs/eigen/common.h"
|
||||
#include "paddle/phi/kernels/funcs/math.h"
|
||||
#include "paddle/phi/kernels/funcs/math_function.h"
|
||||
#include "paddle/phi/kernels/funcs/softmax.h"
|
||||
#include "paddle/phi/kernels/funcs/softmax_impl.h"
|
||||
#include "paddle/phi/kernels/reduce_sum_kernel.h"
|
||||
#include "paddle/utils/string/string_helper.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
static constexpr int kNumCUDAThreads = 512;
|
||||
static constexpr int64_t kNumMaximumNumBlocks = 4096;
|
||||
|
||||
static inline int64_t NumBlocks(const int64_t N) {
|
||||
return std::min((N + kNumCUDAThreads - 1) / kNumCUDAThreads,
|
||||
kNumMaximumNumBlocks);
|
||||
}
|
||||
|
||||
template <typename T, typename IndexT>
|
||||
__global__ void CalculateSoftLogitsGrad(T* logits_grad,
|
||||
IndexT* is_ignore,
|
||||
const IndexT* labels,
|
||||
const IndexT ignore_index,
|
||||
const int64_t start_index,
|
||||
const int64_t end_index,
|
||||
const int64_t N,
|
||||
const int64_t D,
|
||||
const int64_t C) {
|
||||
const T prob = static_cast<T>(1.0 / C);
|
||||
CUDA_KERNEL_LOOP_TYPE(i, N, int64_t) {
|
||||
is_ignore[i] = labels[i * C];
|
||||
for (int j = 0; j < C; ++j) {
|
||||
auto real_label = labels[i * C + j];
|
||||
if (real_label == ignore_index) {
|
||||
is_ignore[i] = real_label;
|
||||
}
|
||||
if (real_label >= start_index && real_label < end_index) {
|
||||
int64_t idx = i * D + real_label - start_index;
|
||||
logits_grad[idx] = logits_grad[idx] - prob;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename IndexT>
|
||||
__global__ void SoftMaskLabelByIndexGrad(T* logits_grad,
|
||||
const T* loss_grad,
|
||||
const IndexT* is_ignore,
|
||||
const int64_t start_index,
|
||||
const int64_t end_index,
|
||||
const int64_t N,
|
||||
const int64_t D,
|
||||
const int64_t ignore_index) {
|
||||
CUDA_KERNEL_LOOP_TYPE(i, N * D, int64_t) {
|
||||
auto row = i / D;
|
||||
auto col = i % D;
|
||||
auto lbl = static_cast<int64_t>(is_ignore[row]);
|
||||
if (lbl == ignore_index) {
|
||||
logits_grad[i] = static_cast<T>(0.0);
|
||||
} else {
|
||||
logits_grad[i] *= loss_grad[row];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename IndexT>
|
||||
__global__ void MaskLabelByIndexGrad(T* logits_grad,
|
||||
const T* loss_grad,
|
||||
const IndexT* labels,
|
||||
const int64_t start_index,
|
||||
const int64_t end_index,
|
||||
const int64_t N,
|
||||
const int64_t D,
|
||||
const int64_t ignore_index) {
|
||||
CUDA_KERNEL_LOOP_TYPE(i, N * D, int64_t) {
|
||||
auto row = i / D;
|
||||
auto col = i % D;
|
||||
auto lbl = static_cast<int64_t>(labels[row]);
|
||||
if (lbl == ignore_index) {
|
||||
logits_grad[i] = static_cast<T>(0.0);
|
||||
} else if ((col + start_index) == labels[row]) {
|
||||
logits_grad[i] = (logits_grad[i] - static_cast<T>(1.0)) * loss_grad[row];
|
||||
} else {
|
||||
logits_grad[i] *= loss_grad[row];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void CSoftmaxWithCrossEntropyGradKernel(const Context& dev_ctx,
|
||||
const DenseTensor& softmax_in,
|
||||
const DenseTensor& label_in,
|
||||
const DenseTensor& loss_grad_in,
|
||||
int64_t ignore_index,
|
||||
int rank,
|
||||
int nranks,
|
||||
DenseTensor* logits_grad) {
|
||||
const DenseTensor* labels = &label_in;
|
||||
const DenseTensor* loss_grad = &loss_grad_in;
|
||||
const DenseTensor* softmax = &softmax_in;
|
||||
DenseTensor* logit_grad = logits_grad;
|
||||
|
||||
if (logit_grad != softmax) {
|
||||
Copy(dev_ctx, *softmax, dev_ctx.GetPlace(), false, logit_grad);
|
||||
}
|
||||
const auto softmax_dims = softmax->dims();
|
||||
const int axis = softmax_dims.size() - 1;
|
||||
const int64_t N = funcs::SizeToAxis<int64_t>(axis, softmax_dims);
|
||||
const int64_t D = funcs::SizeFromAxis<int64_t>(axis, softmax_dims);
|
||||
|
||||
const auto label_dims = labels->dims();
|
||||
const int64_t C = label_dims[axis];
|
||||
|
||||
DenseTensor logit_grad_2d;
|
||||
logit_grad_2d.ShareDataWith(*logit_grad).Resize({N, D});
|
||||
|
||||
int64_t blocks = NumBlocks(N * D);
|
||||
int64_t blocks_cal = NumBlocks(N);
|
||||
int threads = kNumCUDAThreads;
|
||||
const auto& label_type = labels->dtype();
|
||||
const int64_t start_index = rank * D;
|
||||
const int64_t end_index = start_index + D;
|
||||
|
||||
if (label_type == DataType::INT32) {
|
||||
if (C > 1) {
|
||||
DenseTensor is_ignore;
|
||||
is_ignore.Resize({N, 1});
|
||||
dev_ctx.template Alloc<int32_t>(&is_ignore);
|
||||
|
||||
CalculateSoftLogitsGrad<T, int32_t>
|
||||
<<<blocks_cal, threads, 0, dev_ctx.stream()>>>(
|
||||
logit_grad_2d.data<T>(),
|
||||
is_ignore.data<int32_t>(),
|
||||
labels->data<int32_t>(),
|
||||
ignore_index,
|
||||
start_index,
|
||||
end_index,
|
||||
N,
|
||||
D,
|
||||
C);
|
||||
|
||||
SoftMaskLabelByIndexGrad<T, int32_t>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(logit_grad_2d.data<T>(),
|
||||
loss_grad->data<T>(),
|
||||
is_ignore.data<int32_t>(),
|
||||
start_index,
|
||||
end_index,
|
||||
N,
|
||||
D,
|
||||
ignore_index);
|
||||
} else {
|
||||
MaskLabelByIndexGrad<T, int32_t>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(logit_grad_2d.data<T>(),
|
||||
loss_grad->data<T>(),
|
||||
labels->data<int32_t>(),
|
||||
start_index,
|
||||
end_index,
|
||||
N,
|
||||
D,
|
||||
ignore_index);
|
||||
}
|
||||
} else if (label_type == DataType::INT64) {
|
||||
if (C > 1) {
|
||||
DenseTensor is_ignore;
|
||||
is_ignore.Resize({N, 1});
|
||||
dev_ctx.template Alloc<int32_t>(&is_ignore);
|
||||
|
||||
CalculateSoftLogitsGrad<T, int64_t>
|
||||
<<<blocks_cal, threads, 0, dev_ctx.stream()>>>(
|
||||
logit_grad_2d.data<T>(),
|
||||
is_ignore.data<int64_t>(),
|
||||
labels->data<int64_t>(),
|
||||
ignore_index,
|
||||
start_index,
|
||||
end_index,
|
||||
N,
|
||||
D,
|
||||
C);
|
||||
|
||||
SoftMaskLabelByIndexGrad<T, int64_t>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(logit_grad_2d.data<T>(),
|
||||
loss_grad->data<T>(),
|
||||
is_ignore.data<int64_t>(),
|
||||
start_index,
|
||||
end_index,
|
||||
N,
|
||||
D,
|
||||
ignore_index);
|
||||
} else {
|
||||
MaskLabelByIndexGrad<T, int64_t>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(logit_grad_2d.data<T>(),
|
||||
loss_grad->data<T>(),
|
||||
labels->data<int64_t>(),
|
||||
start_index,
|
||||
end_index,
|
||||
N,
|
||||
D,
|
||||
ignore_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(c_softmax_with_cross_entropy_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CSoftmaxWithCrossEntropyGradKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16) {}
|
||||
@@ -0,0 +1,379 @@
|
||||
// Copyright (c) 2024 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/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/core/platform/collective_helper.h"
|
||||
#include "paddle/phi/kernels/activation_kernel.h"
|
||||
#include "paddle/phi/kernels/full_kernel.h"
|
||||
#include "paddle/phi/kernels/funcs/axis_utils.h"
|
||||
#include "paddle/phi/kernels/funcs/broadcast_function.h"
|
||||
#include "paddle/phi/kernels/funcs/cross_entropy.h"
|
||||
#include "paddle/phi/kernels/funcs/eigen/common.h"
|
||||
#include "paddle/phi/kernels/funcs/elementwise_functor.h"
|
||||
#include "paddle/phi/kernels/funcs/math.h"
|
||||
#include "paddle/phi/kernels/funcs/math_function.h"
|
||||
#include "paddle/phi/kernels/funcs/softmax.h"
|
||||
#include "paddle/phi/kernels/funcs/softmax_impl.h"
|
||||
#include "paddle/phi/kernels/reduce_max_kernel.h"
|
||||
#include "paddle/phi/kernels/reduce_sum_kernel.h"
|
||||
#include "paddle/utils/string/string_helper.h"
|
||||
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
#include "paddle/phi/core/distributed/nccl_comm_context.h"
|
||||
#endif
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename Context, typename T>
|
||||
struct CSoftmaxWithCrossEntropyFunctor {
|
||||
void operator()(const Context& dev_ctx,
|
||||
const DenseTensor& logits,
|
||||
const DenseTensor& label,
|
||||
int64_t ignore_index,
|
||||
int rank,
|
||||
int nranks,
|
||||
DenseTensor* softmax,
|
||||
DenseTensor* loss);
|
||||
};
|
||||
|
||||
static constexpr int kNumCUDAThreads = 512;
|
||||
static constexpr int64_t kNumMaximumNumBlocks = 4096;
|
||||
|
||||
static inline int64_t NumBlocks(const int64_t N) {
|
||||
return std::min((N + kNumCUDAThreads - 1) / kNumCUDAThreads,
|
||||
kNumMaximumNumBlocks);
|
||||
}
|
||||
|
||||
template <typename T, typename IndexT>
|
||||
__global__ void MaskLabelByIndex(T* predicted_logits,
|
||||
const T* logit,
|
||||
const IndexT* label,
|
||||
const IndexT ignore_index,
|
||||
const int64_t start_index,
|
||||
const int64_t end_index,
|
||||
const int64_t N,
|
||||
const int64_t D,
|
||||
const int nranks) {
|
||||
CUDA_KERNEL_LOOP_TYPE(i, N, int64_t) {
|
||||
auto real_label = label[i];
|
||||
PADDLE_ENFORCE(((real_label < D * nranks) && (real_label >= 0)) ||
|
||||
(real_label == ignore_index),
|
||||
"The index is out of bounds, "
|
||||
"please check whether the value of label and "
|
||||
"input meet the class number. It should "
|
||||
"be less than [%ld] or equal to [%ld], but received [%ld]",
|
||||
static_cast<int64_t>(D * nranks),
|
||||
static_cast<int64_t>(ignore_index),
|
||||
static_cast<int64_t>(real_label));
|
||||
|
||||
if (real_label >= start_index && real_label < end_index) {
|
||||
predicted_logits[i] = logit[i * D + real_label - start_index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename IndexT>
|
||||
__global__ void SoftMaskLabelByIndex(T* predicted_logits,
|
||||
const T* logit,
|
||||
const IndexT* label,
|
||||
const IndexT ignore_index,
|
||||
const int64_t start_index,
|
||||
const int64_t end_index,
|
||||
const int64_t N,
|
||||
const int64_t D,
|
||||
const int64_t C,
|
||||
const int nranks) {
|
||||
CUDA_KERNEL_LOOP_TYPE(i, N, int64_t) {
|
||||
for (int j = 0; j < C; ++j) {
|
||||
auto real_label = label[i * C + j];
|
||||
PADDLE_ENFORCE(((real_label < D * nranks) && (real_label >= 0)) ||
|
||||
(real_label == ignore_index),
|
||||
"The index is out of bounds, "
|
||||
"please check whether the value of label and "
|
||||
"input meet the class number. It should "
|
||||
"be less than [%ld] or equal to [%ld], but received [%ld]",
|
||||
static_cast<int64_t>(D * nranks),
|
||||
static_cast<int64_t>(ignore_index),
|
||||
static_cast<int64_t>(real_label));
|
||||
|
||||
if (real_label >= start_index && real_label < end_index) {
|
||||
predicted_logits[i * C + j] = logit[i * D + real_label - start_index];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename IndexT>
|
||||
__global__ void CalculateLoss(T* loss,
|
||||
const T* predict_logits,
|
||||
const T* sum_exp_logits,
|
||||
const IndexT* label,
|
||||
const int64_t ignore_index,
|
||||
const int64_t N) {
|
||||
CUDA_KERNEL_LOOP_TYPE(i, N, int64_t) {
|
||||
auto real_label = static_cast<int64_t>(label[i]);
|
||||
loss[i] = ignore_index == real_label
|
||||
? static_cast<T>(0)
|
||||
: funcs::TolerableValue<T>()(
|
||||
funcs::TolerableValue<T>()(
|
||||
funcs::real_log(sum_exp_logits[i])) -
|
||||
predict_logits[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename IndexT>
|
||||
__global__ void CalculateSoftLoss(T* loss,
|
||||
const T* predict_logits,
|
||||
const T* sum_exp_logits,
|
||||
const IndexT* label,
|
||||
const int64_t ignore_index,
|
||||
const int64_t N,
|
||||
const int64_t C) {
|
||||
const T prob = static_cast<T>(1.0 / C);
|
||||
|
||||
CUDA_KERNEL_LOOP_TYPE(i, N, int64_t) {
|
||||
T tmp_loss = static_cast<T>(0);
|
||||
int ignore_num = 0;
|
||||
for (int j = 0; j < C; ++j) {
|
||||
auto real_label = static_cast<int64_t>(label[i * C + j]);
|
||||
tmp_loss += ignore_index == real_label
|
||||
? static_cast<T>(0)
|
||||
: funcs::TolerableValue<T>()(
|
||||
(funcs::TolerableValue<T>()(
|
||||
funcs::real_log(sum_exp_logits[i])) -
|
||||
predict_logits[i * C + j]) *
|
||||
prob);
|
||||
ignore_num += ignore_index == real_label ? 1 : 0;
|
||||
}
|
||||
loss[i] = ignore_num > 0 ? static_cast<T>(0) : tmp_loss;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void CSoftmaxWithCrossEntropyKernel(const Context& dev_ctx,
|
||||
const DenseTensor& logits,
|
||||
const DenseTensor& label,
|
||||
int64_t ignore_index,
|
||||
int rank,
|
||||
int nranks,
|
||||
DenseTensor* softmax,
|
||||
DenseTensor* loss) {
|
||||
CSoftmaxWithCrossEntropyFunctor<GPUContext, T> functor_;
|
||||
functor_(dev_ctx, logits, label, ignore_index, rank, nranks, softmax, loss);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct CSoftmaxWithCrossEntropyFunctor<GPUContext, T> {
|
||||
void operator()(const GPUContext& dev_ctx,
|
||||
const DenseTensor& logits_in,
|
||||
const DenseTensor& label_in,
|
||||
int64_t ignore_index,
|
||||
int rank,
|
||||
int nranks,
|
||||
DenseTensor* softmax,
|
||||
DenseTensor* loss) {
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
const DenseTensor* logits = &logits_in;
|
||||
const DenseTensor* labels = &label_in;
|
||||
|
||||
gpuStream_t stream = nullptr;
|
||||
distributed::NCCLCommContext* comm_ctx = nullptr;
|
||||
|
||||
comm_ctx =
|
||||
static_cast<distributed::NCCLCommContext*>(dev_ctx.GetCommContext());
|
||||
PADDLE_ENFORCE_NE(comm_ctx,
|
||||
nullptr,
|
||||
common::errors::Unavailable(
|
||||
"NCCLCommContext is nullptr, collective op should "
|
||||
"has ring_id attr."));
|
||||
|
||||
stream = dev_ctx.stream();
|
||||
|
||||
// allocate memory on device.
|
||||
dev_ctx.template Alloc<T>(softmax);
|
||||
dev_ctx.template Alloc<T>(loss);
|
||||
|
||||
const auto& logits_dims = logits->dims();
|
||||
const auto& labels_dims = labels->dims();
|
||||
|
||||
const int axis = logits_dims.size() - 1;
|
||||
const int64_t N = funcs::SizeToAxis<int64_t>(axis, logits_dims);
|
||||
const int64_t D = funcs::SizeFromAxis<int64_t>(axis, logits_dims);
|
||||
const int64_t C = funcs::SizeFromAxis<int64_t>(axis, labels_dims);
|
||||
|
||||
DenseTensor logits_2d, softmax_2d, loss_2d;
|
||||
logits_2d.ShareDataWith(*logits).Resize({N, D});
|
||||
softmax_2d.ShareDataWith(*softmax).Resize({N, D});
|
||||
loss_2d.ShareDataWith(*loss).Resize({N, 1});
|
||||
|
||||
// step 1, obtain logit_max
|
||||
DenseTensor logits_max;
|
||||
logits_max.Resize({N, 1});
|
||||
dev_ctx.template Alloc<T>(&logits_max);
|
||||
|
||||
MaxKernel<T, GPUContext>(dev_ctx, logits_2d, {-1}, true, &logits_max);
|
||||
|
||||
comm_ctx->AllReduce(&logits_max, logits_max, ncclMax, stream);
|
||||
|
||||
// step 2, obtain logit - logit_max
|
||||
std::vector<const DenseTensor*> inputs = {&logits_2d, &logits_max};
|
||||
std::vector<DenseTensor*> outputs = {&softmax_2d};
|
||||
funcs::BroadcastKernel<T>(
|
||||
dev_ctx, inputs, &outputs, funcs::SubtractFunctor<T>());
|
||||
|
||||
// step 3, obtain predict target
|
||||
DenseTensor predicted_logits;
|
||||
predicted_logits.Resize({N, 1});
|
||||
dev_ctx.template Alloc<T>(&predicted_logits);
|
||||
|
||||
Full<T, GPUContext>(dev_ctx, predicted_logits.dims(), 0, &predicted_logits);
|
||||
|
||||
const int64_t start_index = rank * D;
|
||||
const int64_t end_index = start_index + D;
|
||||
|
||||
int64_t blocks = NumBlocks(N);
|
||||
int threads = kNumCUDAThreads;
|
||||
const auto& label_type = labels->dtype();
|
||||
|
||||
if (label_type == DataType::INT32) {
|
||||
if (C > 1) {
|
||||
SoftMaskLabelByIndex<T, int32_t>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
predicted_logits.data<T>(),
|
||||
softmax_2d.data<T>(),
|
||||
labels->data<int32_t>(),
|
||||
static_cast<int32_t>(ignore_index),
|
||||
start_index,
|
||||
end_index,
|
||||
N,
|
||||
D,
|
||||
C,
|
||||
nranks);
|
||||
} else {
|
||||
MaskLabelByIndex<T, int32_t><<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
predicted_logits.data<T>(),
|
||||
softmax_2d.data<T>(),
|
||||
labels->data<int32_t>(),
|
||||
static_cast<int32_t>(ignore_index),
|
||||
start_index,
|
||||
end_index,
|
||||
N,
|
||||
D,
|
||||
nranks);
|
||||
}
|
||||
} else if (label_type == DataType::INT64) {
|
||||
if (C > 1) {
|
||||
SoftMaskLabelByIndex<T, int64_t>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
predicted_logits.data<T>(),
|
||||
softmax_2d.data<T>(),
|
||||
labels->data<int64_t>(),
|
||||
ignore_index,
|
||||
start_index,
|
||||
end_index,
|
||||
N,
|
||||
D,
|
||||
C,
|
||||
nranks);
|
||||
} else {
|
||||
MaskLabelByIndex<T, int64_t><<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
predicted_logits.data<T>(),
|
||||
softmax_2d.data<T>(),
|
||||
labels->data<int64_t>(),
|
||||
ignore_index,
|
||||
start_index,
|
||||
end_index,
|
||||
N,
|
||||
D,
|
||||
nranks);
|
||||
}
|
||||
}
|
||||
|
||||
dev_ctx.template Alloc<T>(&predicted_logits);
|
||||
comm_ctx->AllReduce(&predicted_logits, predicted_logits, ncclSum, stream);
|
||||
|
||||
// step 4, obtain exp(logit)
|
||||
ExpKernel<T, GPUContext>(dev_ctx, softmax_2d, &softmax_2d);
|
||||
|
||||
// step 5, obtain sum_exp_logits
|
||||
DenseTensor sum_exp_logits;
|
||||
sum_exp_logits.Resize({N, 1});
|
||||
dev_ctx.template Alloc<T>(&sum_exp_logits);
|
||||
|
||||
SumKernel<T, GPUContext>(
|
||||
dev_ctx, softmax_2d, {-1}, softmax_2d.dtype(), true, &sum_exp_logits);
|
||||
|
||||
comm_ctx->AllReduce(&sum_exp_logits, sum_exp_logits, ncclSum, stream);
|
||||
|
||||
if (label_type == DataType::INT32) {
|
||||
if (C > 1) {
|
||||
CalculateSoftLoss<T, int32_t><<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
loss_2d.data<T>(),
|
||||
predicted_logits.data<T>(),
|
||||
sum_exp_logits.data<T>(),
|
||||
labels->data<int32_t>(),
|
||||
ignore_index,
|
||||
N,
|
||||
C);
|
||||
} else {
|
||||
CalculateLoss<T, int32_t><<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
loss_2d.data<T>(),
|
||||
predicted_logits.data<T>(),
|
||||
sum_exp_logits.data<T>(),
|
||||
labels->data<int32_t>(),
|
||||
ignore_index,
|
||||
N);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (C > 1) {
|
||||
CalculateSoftLoss<T, int64_t><<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
loss_2d.data<T>(),
|
||||
predicted_logits.data<T>(),
|
||||
sum_exp_logits.data<T>(),
|
||||
labels->data<int64_t>(),
|
||||
ignore_index,
|
||||
N,
|
||||
C);
|
||||
} else {
|
||||
CalculateLoss<T, int64_t><<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
loss_2d.data<T>(),
|
||||
predicted_logits.data<T>(),
|
||||
sum_exp_logits.data<T>(),
|
||||
labels->data<int64_t>(),
|
||||
ignore_index,
|
||||
N);
|
||||
}
|
||||
}
|
||||
|
||||
ReciprocalKernel<T, GPUContext>(dev_ctx, sum_exp_logits, &sum_exp_logits);
|
||||
|
||||
inputs = std::vector<const DenseTensor*>{&softmax_2d, &sum_exp_logits};
|
||||
outputs = std::vector<DenseTensor*>{&softmax_2d};
|
||||
funcs::BroadcastKernel<T>(
|
||||
dev_ctx, inputs, &outputs, funcs::MultiplyFunctor<T>());
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(c_softmax_with_cross_entropy,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CSoftmaxWithCrossEntropyKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16) {}
|
||||
@@ -0,0 +1,161 @@
|
||||
// Copyright (c) 2024 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/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/axis_utils.h"
|
||||
#include "paddle/phi/kernels/funcs/cross_entropy.h"
|
||||
#include "paddle/phi/kernels/funcs/eigen/common.h"
|
||||
#include "paddle/phi/kernels/funcs/math.h"
|
||||
#include "paddle/phi/kernels/funcs/math_function.h"
|
||||
#include "paddle/phi/kernels/funcs/softmax.h"
|
||||
#include "paddle/phi/kernels/funcs/softmax_impl.h"
|
||||
#include "paddle/phi/kernels/reduce_sum_kernel.h"
|
||||
#include "paddle/utils/string/string_helper.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
static constexpr int kNumCUDAThreads = 512;
|
||||
static constexpr int64_t kNumMaximumNumBlocks = 4096;
|
||||
|
||||
static inline int64_t NumBlocks(const int64_t N) {
|
||||
return std::min((N + kNumCUDAThreads - 1) / kNumCUDAThreads,
|
||||
kNumMaximumNumBlocks);
|
||||
}
|
||||
|
||||
template <typename T, typename IndexT>
|
||||
__global__ void CalculateSoftLogitsGrad(T* logits_grad,
|
||||
const IndexT* labels,
|
||||
const T* smooth_weight,
|
||||
const IndexT ignore_index,
|
||||
const int64_t start_index,
|
||||
const int64_t end_index,
|
||||
const int64_t N,
|
||||
const int64_t D,
|
||||
const int64_t C) {
|
||||
CUDA_KERNEL_LOOP_TYPE(i, N, int64_t) {
|
||||
for (int j = 0; j < C; ++j) {
|
||||
auto real_label = labels[i * C + j];
|
||||
auto prob = smooth_weight[i * C + j];
|
||||
if (real_label >= start_index && real_label < end_index) {
|
||||
int64_t idx = i * D + real_label - start_index;
|
||||
logits_grad[idx] = real_label == ignore_index
|
||||
? static_cast<T>(0)
|
||||
: (logits_grad[idx] - prob);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename IndexT>
|
||||
__global__ void SoftMaskLabelByIndexGrad(T* logits_grad,
|
||||
const T* loss_grad,
|
||||
const int64_t N,
|
||||
const int64_t D,
|
||||
const int64_t C,
|
||||
const bool sum_multi_label_loss) {
|
||||
CUDA_KERNEL_LOOP_TYPE(i, N * D, int64_t) {
|
||||
auto loss_grad_idx = sum_multi_label_loss ? (i / D) : (i / D * C);
|
||||
logits_grad[i] *= loss_grad[loss_grad_idx];
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void CSoftmaxWithMultiLabelCrossEntropyGradKernel(
|
||||
const Context& dev_ctx,
|
||||
const DenseTensor& softmax_in,
|
||||
const DenseTensor& label_in,
|
||||
const DenseTensor& smooth_weight_in,
|
||||
const DenseTensor& loss_grad_in,
|
||||
int64_t ignore_index,
|
||||
bool sum_multi_label_loss,
|
||||
int rank,
|
||||
int nranks,
|
||||
DenseTensor* logits_grad) {
|
||||
const DenseTensor* labels = &label_in;
|
||||
const DenseTensor* smooth_weight = &smooth_weight_in;
|
||||
const DenseTensor* loss_grad = &loss_grad_in;
|
||||
const DenseTensor* softmax = &softmax_in;
|
||||
DenseTensor* logit_grad = logits_grad;
|
||||
|
||||
if (logit_grad != softmax) {
|
||||
Copy(dev_ctx, *softmax, dev_ctx.GetPlace(), false, logit_grad);
|
||||
}
|
||||
const auto softmax_dims = softmax->dims();
|
||||
const int axis = softmax_dims.size() - 1;
|
||||
const int64_t N = funcs::SizeToAxis<int64_t>(axis, softmax_dims);
|
||||
const int64_t D = funcs::SizeFromAxis<int64_t>(axis, softmax_dims);
|
||||
|
||||
const auto label_dims = labels->dims();
|
||||
const int64_t C = label_dims[axis];
|
||||
|
||||
DenseTensor logit_grad_2d;
|
||||
logit_grad_2d.ShareDataWith(*logit_grad).Resize({N, D});
|
||||
|
||||
int64_t blocks = NumBlocks(N * D);
|
||||
int64_t blocks_cal = NumBlocks(N);
|
||||
int threads = kNumCUDAThreads;
|
||||
const auto& label_type = labels->dtype();
|
||||
const int64_t start_index = rank * D;
|
||||
const int64_t end_index = start_index + D;
|
||||
|
||||
if (label_type == DataType::INT32) {
|
||||
CalculateSoftLogitsGrad<T, int32_t>
|
||||
<<<blocks_cal, threads, 0, dev_ctx.stream()>>>(logit_grad_2d.data<T>(),
|
||||
labels->data<int32_t>(),
|
||||
smooth_weight->data<T>(),
|
||||
ignore_index,
|
||||
start_index,
|
||||
end_index,
|
||||
N,
|
||||
D,
|
||||
C);
|
||||
|
||||
SoftMaskLabelByIndexGrad<T, int32_t>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(logit_grad_2d.data<T>(),
|
||||
loss_grad->data<T>(),
|
||||
N,
|
||||
D,
|
||||
C,
|
||||
sum_multi_label_loss);
|
||||
} else if (label_type == DataType::INT64) {
|
||||
CalculateSoftLogitsGrad<T, int64_t>
|
||||
<<<blocks_cal, threads, 0, dev_ctx.stream()>>>(logit_grad_2d.data<T>(),
|
||||
labels->data<int64_t>(),
|
||||
smooth_weight->data<T>(),
|
||||
ignore_index,
|
||||
start_index,
|
||||
end_index,
|
||||
N,
|
||||
D,
|
||||
C);
|
||||
|
||||
SoftMaskLabelByIndexGrad<T, int64_t>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(logit_grad_2d.data<T>(),
|
||||
loss_grad->data<T>(),
|
||||
N,
|
||||
D,
|
||||
C,
|
||||
sum_multi_label_loss);
|
||||
}
|
||||
}
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(c_softmax_with_multi_label_cross_entropy_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CSoftmaxWithMultiLabelCrossEntropyGradKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16) {}
|
||||
@@ -0,0 +1,315 @@
|
||||
// Copyright (c) 2024 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/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/core/platform/collective_helper.h"
|
||||
#include "paddle/phi/kernels/funcs/axis_utils.h"
|
||||
#include "paddle/phi/kernels/funcs/cross_entropy.h"
|
||||
#include "paddle/phi/kernels/funcs/eigen/common.h"
|
||||
#include "paddle/phi/kernels/funcs/math.h"
|
||||
#include "paddle/phi/kernels/funcs/math_function.h"
|
||||
#include "paddle/phi/kernels/funcs/softmax.h"
|
||||
#include "paddle/phi/kernels/funcs/softmax_impl.h"
|
||||
#include "paddle/phi/kernels/reduce_sum_kernel.h"
|
||||
#include "paddle/utils/string/string_helper.h"
|
||||
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
#include "paddle/phi/core/distributed/nccl_comm_context.h"
|
||||
#endif
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename Context, typename T>
|
||||
struct CSoftmaxWithMultiLabelCrossEntropyFunctor {
|
||||
void operator()(const Context& dev_ctx,
|
||||
const DenseTensor& logits,
|
||||
const DenseTensor& label,
|
||||
const DenseTensor& smooth_weight,
|
||||
int64_t ignore_index,
|
||||
bool sum_multi_label_loss,
|
||||
int rank,
|
||||
int nranks,
|
||||
DenseTensor* softmax,
|
||||
DenseTensor* loss);
|
||||
};
|
||||
|
||||
static constexpr int kNumCUDAThreads = 512;
|
||||
static constexpr int64_t kNumMaximumNumBlocks = 4096;
|
||||
|
||||
static inline int64_t NumBlocks(const int64_t N) {
|
||||
return std::min((N + kNumCUDAThreads - 1) / kNumCUDAThreads,
|
||||
kNumMaximumNumBlocks);
|
||||
}
|
||||
|
||||
template <typename T, typename IndexT>
|
||||
__global__ void SoftMaskLabelByIndex(T* predicted_logits,
|
||||
const T* logit,
|
||||
const IndexT* label,
|
||||
const IndexT ignore_index,
|
||||
const int64_t start_index,
|
||||
const int64_t end_index,
|
||||
const int64_t N,
|
||||
const int64_t D,
|
||||
const int64_t C,
|
||||
const int nranks) {
|
||||
CUDA_KERNEL_LOOP_TYPE(i, N, int64_t) {
|
||||
for (int j = 0; j < C; ++j) {
|
||||
auto real_label = label[i * C + j];
|
||||
PADDLE_ENFORCE(((real_label < D * nranks) && (real_label >= 0)) ||
|
||||
(real_label == ignore_index),
|
||||
"The index is out of bounds, "
|
||||
"please check whether the value of label and "
|
||||
"input meet the class number. It should "
|
||||
"be less than [%ld] or equal to [%ld], but received [%ld]",
|
||||
static_cast<int64_t>(D * nranks),
|
||||
static_cast<int64_t>(ignore_index),
|
||||
static_cast<int64_t>(real_label));
|
||||
|
||||
if (real_label >= start_index && real_label < end_index) {
|
||||
predicted_logits[i * C + j] = logit[i * D + real_label - start_index];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename IndexT>
|
||||
__global__ void CalculateSoftLoss(T* loss,
|
||||
const T* predict_logits,
|
||||
const T* sum_exp_logits,
|
||||
const IndexT* label,
|
||||
const T* smooth_weight,
|
||||
const int64_t ignore_index,
|
||||
const int64_t N,
|
||||
const int64_t C,
|
||||
const bool sum_multi_label_loss) {
|
||||
CUDA_KERNEL_LOOP_TYPE(i, N, int64_t) {
|
||||
T tmp_loss = static_cast<T>(0);
|
||||
loss[i] = static_cast<T>(0);
|
||||
T log_sum_exp_logits =
|
||||
funcs::TolerableValue<T>()(funcs::real_log(sum_exp_logits[i]));
|
||||
for (int j = 0; j < C; ++j) {
|
||||
int64_t label_idx = i * C + j;
|
||||
auto real_label = static_cast<int64_t>(label[label_idx]);
|
||||
auto prob = static_cast<T>(smooth_weight[label_idx]);
|
||||
tmp_loss =
|
||||
ignore_index == real_label
|
||||
? static_cast<T>(0)
|
||||
: funcs::TolerableValue<T>()(
|
||||
(log_sum_exp_logits - predict_logits[label_idx]) * prob);
|
||||
if (sum_multi_label_loss) {
|
||||
loss[i] += tmp_loss;
|
||||
} else {
|
||||
loss[label_idx] = tmp_loss;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void CSoftmaxWithMultiLabelCrossEntropyKernel(const Context& dev_ctx,
|
||||
const DenseTensor& logits,
|
||||
const DenseTensor& label,
|
||||
const DenseTensor& smooth_weight,
|
||||
int64_t ignore_index,
|
||||
bool sum_multi_label_loss,
|
||||
int rank,
|
||||
int nranks,
|
||||
DenseTensor* softmax,
|
||||
DenseTensor* loss) {
|
||||
CSoftmaxWithMultiLabelCrossEntropyFunctor<GPUContext, T> functor_;
|
||||
functor_(dev_ctx,
|
||||
logits,
|
||||
label,
|
||||
smooth_weight,
|
||||
ignore_index,
|
||||
sum_multi_label_loss,
|
||||
rank,
|
||||
nranks,
|
||||
softmax,
|
||||
loss);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct CSoftmaxWithMultiLabelCrossEntropyFunctor<GPUContext, T> {
|
||||
void operator()(const GPUContext& dev_ctx,
|
||||
const DenseTensor& logits_in,
|
||||
const DenseTensor& label_in,
|
||||
const DenseTensor& smooth_weight_in,
|
||||
int64_t ignore_index,
|
||||
bool sum_multi_label_loss,
|
||||
int rank,
|
||||
int nranks,
|
||||
DenseTensor* softmax,
|
||||
DenseTensor* loss) {
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
const DenseTensor* logits = &logits_in;
|
||||
const DenseTensor* labels = &label_in;
|
||||
const DenseTensor* smooth_weight = &smooth_weight_in;
|
||||
|
||||
gpuStream_t stream = nullptr;
|
||||
distributed::NCCLCommContext* comm_ctx = nullptr;
|
||||
|
||||
comm_ctx =
|
||||
static_cast<distributed::NCCLCommContext*>(dev_ctx.GetCommContext());
|
||||
PADDLE_ENFORCE_NE(comm_ctx,
|
||||
nullptr,
|
||||
common::errors::Unavailable(
|
||||
"NCCLCommContext is nullptr, collective op should "
|
||||
"has ring_id attr."));
|
||||
|
||||
stream = dev_ctx.stream();
|
||||
|
||||
// allocate memory on device.
|
||||
dev_ctx.template Alloc<T>(softmax);
|
||||
dev_ctx.template Alloc<T>(loss);
|
||||
|
||||
const auto& logits_dims = logits->dims();
|
||||
const auto& labels_dims = labels->dims();
|
||||
|
||||
const int axis = logits_dims.size() - 1;
|
||||
const int64_t N = funcs::SizeToAxis<int64_t>(axis, logits_dims);
|
||||
const int64_t D = funcs::SizeFromAxis<int64_t>(axis, logits_dims);
|
||||
const int64_t C = funcs::SizeFromAxis<int64_t>(axis, labels_dims);
|
||||
|
||||
DenseTensor logits_2d, softmax_2d, loss_2d;
|
||||
logits_2d.ShareDataWith(*logits).Resize({N, D});
|
||||
softmax_2d.ShareDataWith(*softmax).Resize({N, D});
|
||||
int64_t loss_last_dim = sum_multi_label_loss ? 1 : C;
|
||||
loss_2d.ShareDataWith(*loss).Resize({N, loss_last_dim});
|
||||
|
||||
auto eigen_logits = funcs::EigenMatrix<T>::From(logits_2d);
|
||||
auto eigen_softmax = funcs::EigenMatrix<T>::From(softmax_2d);
|
||||
|
||||
// step 1, obtain logit_max
|
||||
DenseTensor logits_max;
|
||||
logits_max.Resize({N, 1});
|
||||
dev_ctx.template Alloc<T>(&logits_max);
|
||||
|
||||
auto eigen_logits_max = funcs::EigenMatrix<T>::From(logits_max);
|
||||
Eigen::DSizes<int, 1> along_axis(1);
|
||||
eigen_logits_max.device(*dev_ctx.eigen_device()) =
|
||||
eigen_logits.maximum(along_axis);
|
||||
|
||||
comm_ctx->AllReduce(&logits_max, logits_max, ncclMax, stream);
|
||||
|
||||
// step 2, obtain logit - logit_max
|
||||
Eigen::DSizes<int, 2> batch_by_one(N, 1);
|
||||
Eigen::DSizes<int, 2> one_by_class(1, D);
|
||||
|
||||
eigen_softmax.device(*dev_ctx.eigen_device()) =
|
||||
(eigen_logits -
|
||||
eigen_logits_max.reshape(batch_by_one).broadcast(one_by_class));
|
||||
|
||||
// step 3, obtain predict target
|
||||
DenseTensor predicted_logits;
|
||||
predicted_logits.Resize({N, C});
|
||||
dev_ctx.template Alloc<T>(&predicted_logits);
|
||||
|
||||
auto t = EigenVector<T>::Flatten(predicted_logits);
|
||||
t.device(*dev_ctx.eigen_device()) = t.constant(static_cast<T>(0));
|
||||
|
||||
const int64_t start_index = rank * D;
|
||||
const int64_t end_index = start_index + D;
|
||||
|
||||
int64_t blocks = NumBlocks(N);
|
||||
int threads = kNumCUDAThreads;
|
||||
const auto& label_type = labels->dtype();
|
||||
|
||||
if (label_type == DataType::INT32) {
|
||||
SoftMaskLabelByIndex<T, int32_t>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
predicted_logits.data<T>(),
|
||||
softmax_2d.data<T>(),
|
||||
labels->data<int32_t>(),
|
||||
static_cast<int32_t>(ignore_index),
|
||||
start_index,
|
||||
end_index,
|
||||
N,
|
||||
D,
|
||||
C,
|
||||
nranks);
|
||||
} else if (label_type == DataType::INT64) {
|
||||
SoftMaskLabelByIndex<T, int64_t>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
predicted_logits.data<T>(),
|
||||
softmax_2d.data<T>(),
|
||||
labels->data<int64_t>(),
|
||||
static_cast<int32_t>(ignore_index),
|
||||
start_index,
|
||||
end_index,
|
||||
N,
|
||||
D,
|
||||
C,
|
||||
nranks);
|
||||
}
|
||||
|
||||
dev_ctx.template Alloc<T>(&predicted_logits);
|
||||
comm_ctx->AllReduce(&predicted_logits, predicted_logits, ncclSum, stream);
|
||||
|
||||
// step 4, obtain exp(logit)
|
||||
eigen_softmax.device(*dev_ctx.eigen_device()) = eigen_softmax.exp();
|
||||
|
||||
// step 5, obtain sum_exp_logits
|
||||
DenseTensor sum_exp_logits;
|
||||
sum_exp_logits.Resize({N, 1});
|
||||
dev_ctx.template Alloc<T>(&sum_exp_logits);
|
||||
|
||||
SumKernel<T, GPUContext>(
|
||||
dev_ctx, softmax_2d, {-1}, softmax_2d.dtype(), true, &sum_exp_logits);
|
||||
|
||||
comm_ctx->AllReduce(&sum_exp_logits, sum_exp_logits, ncclSum, stream);
|
||||
|
||||
if (label_type == DataType::INT32) {
|
||||
CalculateSoftLoss<T, int32_t>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(loss_2d.data<T>(),
|
||||
predicted_logits.data<T>(),
|
||||
sum_exp_logits.data<T>(),
|
||||
labels->data<int32_t>(),
|
||||
smooth_weight->data<T>(),
|
||||
ignore_index,
|
||||
N,
|
||||
C,
|
||||
sum_multi_label_loss);
|
||||
|
||||
} else {
|
||||
CalculateSoftLoss<T, int64_t>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(loss_2d.data<T>(),
|
||||
predicted_logits.data<T>(),
|
||||
sum_exp_logits.data<T>(),
|
||||
labels->data<int64_t>(),
|
||||
smooth_weight->data<T>(),
|
||||
ignore_index,
|
||||
N,
|
||||
C,
|
||||
sum_multi_label_loss);
|
||||
}
|
||||
|
||||
auto eigen_sum_exp_logits = funcs::EigenMatrix<T>::From(sum_exp_logits);
|
||||
eigen_softmax.device(*dev_ctx.eigen_device()) =
|
||||
(eigen_softmax *
|
||||
eigen_sum_exp_logits.inverse().broadcast(one_by_class));
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(c_softmax_with_multi_label_cross_entropy,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CSoftmaxWithMultiLabelCrossEntropyKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16) {}
|
||||
@@ -0,0 +1,113 @@
|
||||
// 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/c_split_kernel.h"
|
||||
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
static constexpr int64_t kNumCUDAThreads = 512;
|
||||
static constexpr int64_t kNumMaximumNumBlocks = 4096;
|
||||
|
||||
static inline int64_t NumBlocks(const int64_t N) {
|
||||
return std::min((N + kNumCUDAThreads - 1) / kNumCUDAThreads,
|
||||
kNumMaximumNumBlocks);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void SplitFromRank(const T* input,
|
||||
T* output,
|
||||
const int64_t rows,
|
||||
const int64_t columns,
|
||||
const int rank,
|
||||
const int nranks,
|
||||
const int64_t limit) {
|
||||
CUDA_KERNEL_LOOP_TYPE(i, limit, int64_t) {
|
||||
int64_t row = i / columns;
|
||||
int64_t col = i % columns;
|
||||
|
||||
int64_t block = columns / nranks;
|
||||
int64_t start = block * rank;
|
||||
int64_t end = start + block;
|
||||
|
||||
if (col >= start && col < end) {
|
||||
int64_t idx = block * row + col % block;
|
||||
output[idx] = input[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void CSplitKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
int rank,
|
||||
int nranks,
|
||||
bool use_model_parallel,
|
||||
DenseTensor* out) {
|
||||
auto place = dev_ctx.GetPlace();
|
||||
|
||||
PADDLE_ENFORCE_GE(rank,
|
||||
0,
|
||||
common::errors::PreconditionNotMet(
|
||||
"The value of rank (%d) for c_split must be "
|
||||
"greater than or equal to 0.",
|
||||
rank));
|
||||
PADDLE_ENFORCE_GE(nranks,
|
||||
2,
|
||||
common::errors::PreconditionNotMet(
|
||||
"The value of nranks (%d) for c_split must be "
|
||||
"greater than or equal to 2.",
|
||||
nranks));
|
||||
PADDLE_ENFORCE_LT(rank,
|
||||
nranks,
|
||||
common::errors::PreconditionNotMet(
|
||||
"The value of rank (%d) for c_split must be "
|
||||
"less than that of nranks (%d).",
|
||||
rank,
|
||||
nranks));
|
||||
|
||||
auto dims = x.dims();
|
||||
auto dims_size = dims.size();
|
||||
// final dim
|
||||
int64_t end_size = dims[dims_size - 1];
|
||||
|
||||
// remain dim
|
||||
auto remain_ddim = slice_ddim(dims, 0, dims_size - 1);
|
||||
int64_t remain_numel = common::product(remain_ddim);
|
||||
|
||||
int64_t limit = x.numel();
|
||||
int64_t blocks = NumBlocks(limit);
|
||||
int64_t threads = kNumCUDAThreads;
|
||||
|
||||
dims[dims_size - 1] /= nranks;
|
||||
out->Resize(dims);
|
||||
dev_ctx.template Alloc<T>(out);
|
||||
|
||||
SplitFromRank<T><<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
x.data<T>(), out->data<T>(), remain_numel, end_size, rank, nranks, limit);
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(c_split,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CSplitKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::bfloat16,
|
||||
phi::float16) {}
|
||||
@@ -0,0 +1,140 @@
|
||||
// Copyright (c) 2024 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/calc_reduced_attn_kernel.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/core/tensor_utils.h"
|
||||
#include "paddle/phi/kernels/funcs/math_function.h"
|
||||
#include "paddle/phi/kernels/gpu/flash_attn_utils.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
#if defined(PADDLE_WITH_FLASHATTN) && !defined(PADDLE_WITH_HIP)
|
||||
struct CalcReducedAttnScoresParams : public FlashAttnParamsBase {
|
||||
bool return_softmax;
|
||||
DenseTensor* softmax;
|
||||
|
||||
CalcReducedAttnScoresParams(const GPUContext& dev_ctx,
|
||||
const int _batch_size,
|
||||
const int64_t _max_seqlen_q,
|
||||
const int64_t _max_seqlen_k,
|
||||
const int _num_heads,
|
||||
const int _num_heads_k,
|
||||
const int _head_size,
|
||||
const float _scale,
|
||||
const DataType q_dtype)
|
||||
: FlashAttnParamsBase(/*version=*/2,
|
||||
/*is_fwd=*/true,
|
||||
_batch_size,
|
||||
_max_seqlen_q,
|
||||
_max_seqlen_k,
|
||||
_num_heads,
|
||||
_num_heads_k,
|
||||
_head_size,
|
||||
_scale,
|
||||
/*_causal=*/false,
|
||||
q_dtype,
|
||||
optional<DenseTensor>{},
|
||||
optional<DenseTensor>{},
|
||||
/*_unpadded_lse=*/false,
|
||||
/*_total_q*/ 0) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename T, typename Context>
|
||||
void CalcReducedAttnScoresKernel(const Context& dev_ctx,
|
||||
const DenseTensor& q,
|
||||
const DenseTensor& k,
|
||||
const DenseTensor& softmax_lse,
|
||||
DenseTensor* reduced_scores) {
|
||||
#if defined(PADDLE_WITH_FLASHATTN) && !defined(PADDLE_WITH_HIP)
|
||||
PADDLE_ENFORCE_EQ(q.dims().size(),
|
||||
4,
|
||||
common::errors::InvalidArgument(
|
||||
"calc_reduced_attention receive input with dim "
|
||||
"[batch_size, seq_len, num_heads, head_dim]"));
|
||||
|
||||
PADDLE_ENFORCE_EQ(k.dims().size(),
|
||||
4,
|
||||
common::errors::InvalidArgument(
|
||||
"calc_reduced_attention receive input with dim "
|
||||
"[batch_size, seq_len, num_heads, head_dim]"));
|
||||
|
||||
if (!reduced_scores->IsInitialized())
|
||||
dev_ctx.template Alloc<float>(reduced_scores);
|
||||
funcs::SetConstant<Context, float> set_zero;
|
||||
set_zero(dev_ctx, reduced_scores, 0.0f);
|
||||
// q, k, v [batch_size, seq_len, num_heads, head_dim]
|
||||
const int64_t batch_size = q.dims()[0];
|
||||
const int64_t seqlen_q = q.dims()[1];
|
||||
const int64_t num_heads = q.dims()[2];
|
||||
const int64_t head_size = q.dims()[3];
|
||||
const int64_t seqlen_k = k.dims()[1];
|
||||
const int64_t num_heads_k = k.dims()[2];
|
||||
|
||||
const float softmax_scale = 1.0f / std::sqrt(head_size);
|
||||
const float softmax_unscale = std::sqrt(head_size);
|
||||
|
||||
using Params = CalcReducedAttnScoresParams;
|
||||
|
||||
Params params = Params(dev_ctx,
|
||||
batch_size,
|
||||
seqlen_q,
|
||||
seqlen_k,
|
||||
num_heads,
|
||||
num_heads_k,
|
||||
head_size,
|
||||
softmax_scale,
|
||||
q.dtype());
|
||||
|
||||
cudaStream_t stream = dev_ctx.stream();
|
||||
|
||||
bool succ = dynload::calc_reduced_attn_scores(q.data(),
|
||||
k.data(),
|
||||
softmax_lse.data(),
|
||||
reduced_scores->data(),
|
||||
/*softmax_ptr=*/nullptr,
|
||||
params.batch_size,
|
||||
params.max_seqlen_q,
|
||||
params.max_seqlen_k,
|
||||
params.num_heads,
|
||||
params.num_heads_k,
|
||||
params.head_size,
|
||||
params.softmax_scale,
|
||||
/*return_softmax=*/false,
|
||||
params.is_bf16,
|
||||
/*num_splits=*/0,
|
||||
stream,
|
||||
q.strides()[1],
|
||||
k.strides()[1],
|
||||
reduced_scores->strides()[1],
|
||||
q.strides()[2],
|
||||
k.strides()[2],
|
||||
reduced_scores->strides()[2],
|
||||
q.strides()[0],
|
||||
k.strides()[0],
|
||||
reduced_scores->strides()[0]);
|
||||
CheckFlashAttnStatus(succ);
|
||||
#else
|
||||
RaiseNotSupportedError();
|
||||
#endif
|
||||
}
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(calc_reduced_attn_scores,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CalcReducedAttnScoresKernel,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,56 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/kernels/funcs/elementwise_base.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename InT, typename OutT>
|
||||
struct CastFunctor {
|
||||
__device__ __forceinline__ OutT operator()(const InT x) const {
|
||||
return static_cast<OutT>(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename InT, typename OutT>
|
||||
void CastCUDAKernelImpl(const GPUContext& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
DataType out_dtype,
|
||||
DenseTensor* out) {
|
||||
std::vector<const DenseTensor*> inputs;
|
||||
std::vector<DenseTensor*> outputs;
|
||||
inputs.emplace_back(&x);
|
||||
outputs.emplace_back(out);
|
||||
dev_ctx.Alloc<OutT>(out);
|
||||
out->set_type(out_dtype);
|
||||
if (out->numel() == 0) return;
|
||||
funcs::ElementwiseKernel<OutT>(
|
||||
dev_ctx, inputs, &outputs, CastFunctor<InT, OutT>());
|
||||
}
|
||||
|
||||
template <typename InT>
|
||||
void CastCUDAKernel(const GPUContext& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
DataType out_dtype,
|
||||
DenseTensor* out) {
|
||||
PD_VISIT_ALL_TYPES(out_dtype, "CastCUDAKernelImpl", ([&] {
|
||||
CastCUDAKernelImpl<InT, data_t>(
|
||||
dev_ctx, x, out_dtype, out);
|
||||
}));
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
@@ -0,0 +1,83 @@
|
||||
// Copyright (c) 2021 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/cast_kernel.h"
|
||||
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/core/visit_type.h"
|
||||
#include "paddle/phi/kernels/gpu/cast_impl.h"
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void CastKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
DataType out_dtype,
|
||||
DenseTensor* out) {
|
||||
if (x.dtype() == out_dtype) {
|
||||
if (x.dims() == make_ddim({-1})) {
|
||||
*out = x;
|
||||
return;
|
||||
}
|
||||
if (!out->IsSharedWith(x)) {
|
||||
Copy(dev_ctx, x, dev_ctx.GetPlace(), false, out);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (out->IsSharedWith(x)) {
|
||||
auto x_origin = x;
|
||||
CastCUDAKernel<T>(dev_ctx, x_origin, out_dtype, out);
|
||||
} else {
|
||||
CastCUDAKernel<T>(dev_ctx, x, out_dtype, out);
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
INSTANTIATE_CAST_KERNEL(float, GPUContext)
|
||||
INSTANTIATE_CAST_KERNEL(double, GPUContext)
|
||||
INSTANTIATE_CAST_KERNEL(int, GPUContext)
|
||||
INSTANTIATE_CAST_KERNEL(int64_t, GPUContext)
|
||||
INSTANTIATE_CAST_KERNEL(uint8_t, GPUContext)
|
||||
INSTANTIATE_CAST_KERNEL(uint16_t, GPUContext)
|
||||
INSTANTIATE_CAST_KERNEL(uint32_t, GPUContext)
|
||||
INSTANTIATE_CAST_KERNEL(uint64_t, GPUContext)
|
||||
INSTANTIATE_CAST_KERNEL(bool, GPUContext)
|
||||
INSTANTIATE_CAST_KERNEL(int16_t, GPUContext)
|
||||
INSTANTIATE_CAST_KERNEL(float16, GPUContext)
|
||||
INSTANTIATE_CAST_KERNEL(bfloat16, GPUContext)
|
||||
#endif
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(cast,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CastKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
int16_t,
|
||||
bool,
|
||||
int8_t,
|
||||
uint8_t,
|
||||
uint16_t,
|
||||
uint32_t,
|
||||
uint64_t,
|
||||
phi::float16,
|
||||
phi::complex64,
|
||||
phi::complex128,
|
||||
phi::bfloat16,
|
||||
phi::float8_e4m3fn,
|
||||
phi::float8_e5m2) {
|
||||
kernel->OutputAt(0).SetDataType(phi::DataType::UNDEFINED);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/channel_shuffle_grad_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/channel_shuffle_grad_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(channel_shuffle_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ChannelShuffleGradKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/channel_shuffle_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/channel_shuffle_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(channel_shuffle,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ChannelShuffleKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,526 @@
|
||||
/* 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/check_numerics_kernel.h"
|
||||
|
||||
#include "glog/logging.h"
|
||||
#include "paddle/phi/backends/gpu/cuda/cuda_graph_with_memory_pool.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/common/memory_utils.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/check_numerics_utils.h"
|
||||
#include "paddle/phi/kernels/funcs/math_cuda_utils.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
static std::once_flag init_multi_gpu_op_var_map_flag;
|
||||
|
||||
// lazy init
|
||||
static std::vector<std::unordered_map<std::string, Allocator::AllocationPtr>>&
|
||||
multi_op_var2gpu_str() {
|
||||
static std::vector<std::unordered_map<std::string, Allocator::AllocationPtr>>
|
||||
_multi_op_var2gpu_str;
|
||||
return _multi_op_var2gpu_str;
|
||||
}
|
||||
|
||||
static std::vector<std::mutex>& multi_op_var2gpu_str_mutex() {
|
||||
static std::vector<std::mutex> _multi_op_var2gpu_str_mutex;
|
||||
return _multi_op_var2gpu_str_mutex;
|
||||
}
|
||||
|
||||
static void InitMultiGPUOpVarMap() {
|
||||
int dev_count = backends::gpu::GetGPUDeviceCount();
|
||||
PADDLE_ENFORCE_GT(dev_count,
|
||||
0,
|
||||
common::errors::NotFound(
|
||||
"cuda device must > 0, now dev_count=%d", dev_count));
|
||||
|
||||
// https://stackoverflow.com/questions/16465633/how-can-i-use-something-like-stdvectorstdmutex
|
||||
std::vector<std::unordered_map<std::string, Allocator::AllocationPtr>>
|
||||
tmp_multi(dev_count);
|
||||
std::vector<std::mutex> tmp_multi_mutex(dev_count);
|
||||
|
||||
multi_op_var2gpu_str().swap(tmp_multi);
|
||||
multi_op_var2gpu_str_mutex().swap(tmp_multi_mutex);
|
||||
}
|
||||
|
||||
template <typename T, int ReduceType>
|
||||
__device__ T BlockReduce(T value) {
|
||||
__shared__ T shared_mem[1024];
|
||||
|
||||
shared_mem[threadIdx.x] = value;
|
||||
__syncthreads();
|
||||
|
||||
for (int stride = blockDim.x >> 1; stride > 0; stride = stride >> 1) {
|
||||
if (threadIdx.x < stride) {
|
||||
T value0 = shared_mem[threadIdx.x];
|
||||
T value1 = shared_mem[threadIdx.x + stride];
|
||||
T reduce_value;
|
||||
if (ReduceType == 0) {
|
||||
// max
|
||||
reduce_value = value0 > value1 ? value0 : value1;
|
||||
} else if (ReduceType == 1) {
|
||||
// min
|
||||
reduce_value = value0 < value1 ? value0 : value1;
|
||||
} else if (ReduceType == 2) {
|
||||
// sum
|
||||
reduce_value = value0 + value1;
|
||||
}
|
||||
shared_mem[threadIdx.x] = reduce_value;
|
||||
}
|
||||
|
||||
if (stride > 16) {
|
||||
__syncthreads();
|
||||
}
|
||||
}
|
||||
|
||||
__syncthreads();
|
||||
return shared_mem[0];
|
||||
}
|
||||
|
||||
__device__ void BlockReduceNumNanInfAndWrite(const int64_t num_nan,
|
||||
const int64_t num_inf,
|
||||
const int64_t num_zero,
|
||||
int64_t offset,
|
||||
int64_t* num_nan_ptr,
|
||||
int64_t* num_inf_ptr,
|
||||
int64_t* num_zero_ptr) {
|
||||
int64_t block_num_nan = BlockReduce<int64_t, 2>(num_nan);
|
||||
int64_t block_num_inf = BlockReduce<int64_t, 2>(num_inf);
|
||||
int64_t block_num_zero = BlockReduce<int64_t, 2>(num_zero);
|
||||
|
||||
if (threadIdx.x == 0) {
|
||||
num_nan_ptr[offset] = block_num_nan;
|
||||
num_inf_ptr[offset] = block_num_inf;
|
||||
num_zero_ptr[offset] = block_num_zero;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
std::enable_if_t<std::is_same<T, complex64>::value ||
|
||||
std::is_same<T, complex128>::value,
|
||||
bool> = true>
|
||||
__device__ void BlockReduceMaxMinAndWrite(const T max_value,
|
||||
const T min_value,
|
||||
const T mean_value,
|
||||
int64_t offset,
|
||||
T* max_ptr,
|
||||
T* min_ptr,
|
||||
T* mean_ptr) {
|
||||
// TODO(Xreki): support complex
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
std::enable_if_t<!std::is_same<T, complex64>::value &&
|
||||
!std::is_same<T, complex128>::value,
|
||||
bool> = true>
|
||||
__device__ void BlockReduceMaxMinAndWrite(const T max_value,
|
||||
const T min_value,
|
||||
const T mean_value,
|
||||
int64_t offset,
|
||||
T* max_ptr,
|
||||
T* min_ptr,
|
||||
T* mean_ptr) {
|
||||
if (max_ptr && min_ptr && mean_ptr) {
|
||||
__syncthreads();
|
||||
|
||||
T block_max_value = funcs::BlockReduceMax<T>(max_value, FINAL_MASK);
|
||||
T block_min_value = funcs::BlockReduceMin<T>(min_value, FINAL_MASK);
|
||||
T block_mean_value = funcs::BlockReduceSum<T>(mean_value, FINAL_MASK);
|
||||
|
||||
if (threadIdx.x == 0) {
|
||||
max_ptr[offset] = block_max_value;
|
||||
min_ptr[offset] = block_min_value;
|
||||
mean_ptr[offset] = block_mean_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename MT>
|
||||
__global__ void FindNanInfAndBlockMaxMin(const T* value_ptr,
|
||||
const int64_t numel,
|
||||
int64_t* block_num_nan_ptr,
|
||||
int64_t* block_num_inf_ptr,
|
||||
int64_t* block_num_zero_ptr,
|
||||
MT* tensor_block_max_ptr,
|
||||
MT* tensor_block_min_ptr,
|
||||
MT* tensor_block_mean_ptr) {
|
||||
int64_t i =
|
||||
static_cast<int64_t>(threadIdx.x) +
|
||||
static_cast<int64_t>(blockIdx.x) * static_cast<int64_t>(blockDim.x);
|
||||
|
||||
int64_t num_nan = 0;
|
||||
int64_t num_inf = 0;
|
||||
int64_t num_zero = 0;
|
||||
|
||||
MT max_value = static_cast<MT>(i < numel ? value_ptr[i] : value_ptr[0]);
|
||||
MT min_value = static_cast<MT>(i < numel ? value_ptr[i] : value_ptr[0]);
|
||||
MT mean_value = static_cast<MT>(0);
|
||||
for (; i < numel; i += blockDim.x * gridDim.x) {
|
||||
MT value = static_cast<MT>(value_ptr[i]);
|
||||
|
||||
max_value = value > max_value ? value : max_value;
|
||||
min_value = value < min_value ? value : min_value;
|
||||
mean_value += value / static_cast<MT>(numel);
|
||||
|
||||
if (isnan(value)) {
|
||||
num_nan += 1;
|
||||
} else if (isinf(value)) {
|
||||
num_inf += 1;
|
||||
}
|
||||
if (value == static_cast<MT>(0)) {
|
||||
num_zero += 1;
|
||||
}
|
||||
}
|
||||
|
||||
BlockReduceNumNanInfAndWrite(num_nan,
|
||||
num_inf,
|
||||
num_zero,
|
||||
blockIdx.x,
|
||||
block_num_nan_ptr,
|
||||
block_num_inf_ptr,
|
||||
block_num_zero_ptr);
|
||||
|
||||
BlockReduceMaxMinAndWrite<MT>(max_value,
|
||||
min_value,
|
||||
mean_value,
|
||||
blockIdx.x,
|
||||
tensor_block_max_ptr,
|
||||
tensor_block_min_ptr,
|
||||
tensor_block_mean_ptr);
|
||||
}
|
||||
|
||||
template <typename T, typename MT>
|
||||
__global__ void FindGlobalMaxMinAndPrint(const int64_t* block_num_nan_ptr,
|
||||
const int64_t* block_num_inf_ptr,
|
||||
const int64_t* block_num_zero_ptr,
|
||||
const MT* tensor_block_max_ptr,
|
||||
const MT* tensor_block_min_ptr,
|
||||
const MT* tensor_block_mean_ptr,
|
||||
const char* debug_info,
|
||||
int64_t numel,
|
||||
int64_t numel_max_min,
|
||||
int check_nan_inf_level,
|
||||
int64_t* stats_ptr,
|
||||
float* values_ptr) {
|
||||
if (blockIdx.x == 0 && threadIdx.x == 0) {
|
||||
int64_t num_nan = 0;
|
||||
int64_t num_inf = 0;
|
||||
int64_t num_zero = 0;
|
||||
|
||||
// numel_max_min <= 128
|
||||
for (int64_t i = 0; i < numel_max_min; ++i) {
|
||||
num_nan += block_num_nan_ptr[i];
|
||||
num_inf += block_num_inf_ptr[i];
|
||||
num_zero += block_num_zero_ptr[i];
|
||||
}
|
||||
|
||||
MT max_value = static_cast<MT>(0);
|
||||
MT min_value = static_cast<MT>(0);
|
||||
MT mean_value = static_cast<MT>(0);
|
||||
if (tensor_block_max_ptr && tensor_block_min_ptr && tensor_block_mean_ptr) {
|
||||
max_value = tensor_block_max_ptr[0];
|
||||
min_value = tensor_block_min_ptr[0];
|
||||
mean_value = tensor_block_mean_ptr[0];
|
||||
|
||||
// numel_max_min <= 128
|
||||
for (int64_t i = 1; i < numel_max_min; ++i) {
|
||||
MT tmp_max_value = tensor_block_max_ptr[i];
|
||||
MT tmp_min_value = tensor_block_min_ptr[i];
|
||||
MT tmp_mean_value = tensor_block_mean_ptr[i];
|
||||
|
||||
max_value = tmp_max_value > max_value ? tmp_max_value : max_value;
|
||||
min_value = tmp_min_value < min_value ? tmp_min_value : min_value;
|
||||
mean_value += tmp_mean_value;
|
||||
}
|
||||
funcs::SaveStatsAndValues<MT>(num_nan,
|
||||
num_inf,
|
||||
num_zero,
|
||||
max_value,
|
||||
min_value,
|
||||
mean_value,
|
||||
stats_ptr,
|
||||
values_ptr);
|
||||
}
|
||||
|
||||
funcs::PrintForDifferentLevel<T, MT>(debug_info,
|
||||
numel,
|
||||
num_nan,
|
||||
num_inf,
|
||||
num_zero,
|
||||
max_value,
|
||||
min_value,
|
||||
mean_value,
|
||||
check_nan_inf_level);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::string GetHintString(const std::string& op_type,
|
||||
const std::string& var_name,
|
||||
const Place& place,
|
||||
int dev_id = -1) {
|
||||
std::string op_var =
|
||||
funcs::GetCpuHintString<T>(op_type, var_name, place, dev_id);
|
||||
PADDLE_ENFORCE_EQ(
|
||||
(dev_id >= 0 && dev_id < multi_op_var2gpu_str_mutex().size()),
|
||||
true,
|
||||
common::errors::OutOfRange("GPU dev_id must >=0 and < dev_count=%d",
|
||||
multi_op_var2gpu_str_mutex().size()));
|
||||
return op_var;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static char* GetGpuHintStringPtr(const GPUContext& dev_ctx,
|
||||
const std::string& op_type,
|
||||
const std::string& var_name,
|
||||
int dev_id) {
|
||||
std::call_once(init_multi_gpu_op_var_map_flag, InitMultiGPUOpVarMap);
|
||||
|
||||
std::string op_var =
|
||||
GetHintString<T>(op_type, var_name, dev_ctx.GetPlace(), dev_id);
|
||||
char* gpu_str_ptr = nullptr;
|
||||
|
||||
{
|
||||
auto& op_var2gpu_str_mutex = multi_op_var2gpu_str_mutex().at(dev_id);
|
||||
auto& op_var2gpu_str = multi_op_var2gpu_str().at(dev_id);
|
||||
|
||||
std::lock_guard<std::mutex> guard(op_var2gpu_str_mutex);
|
||||
if (op_var2gpu_str.find(op_var) == op_var2gpu_str.end()) { // insert
|
||||
auto gpu_str_tensor = memory_utils::Alloc(
|
||||
dev_ctx.GetPlace(),
|
||||
op_var.length() + 1,
|
||||
Stream(reinterpret_cast<StreamId>(dev_ctx.stream())));
|
||||
gpu_str_ptr = reinterpret_cast<char*>(gpu_str_tensor->ptr());
|
||||
|
||||
op_var2gpu_str.emplace(op_var, std::move(gpu_str_tensor));
|
||||
|
||||
auto iter = op_var2gpu_str.find(op_var);
|
||||
PADDLE_ENFORCE_EQ(iter != op_var2gpu_str.end(),
|
||||
true,
|
||||
common::errors::PreconditionNotMet(
|
||||
"op_var=%s should be successfully insert into "
|
||||
"op_var2gpu_str, but now failed",
|
||||
op_var));
|
||||
|
||||
#ifdef __HIPCC__
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(hipMemcpyAsync(gpu_str_ptr,
|
||||
iter->first.c_str(),
|
||||
op_var.length() + 1,
|
||||
hipMemcpyHostToDevice,
|
||||
dev_ctx.stream()));
|
||||
#else
|
||||
const char* stable_str =
|
||||
backends::gpu::RestoreHostMemIfCapturingCUDAGraph(
|
||||
const_cast<char*>(iter->first.c_str()), op_var.length() + 1);
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(cudaMemcpyAsync(gpu_str_ptr,
|
||||
stable_str,
|
||||
op_var.length() + 1,
|
||||
cudaMemcpyHostToDevice,
|
||||
dev_ctx.stream()));
|
||||
#endif
|
||||
} else { // get
|
||||
auto iter = op_var2gpu_str.find(op_var);
|
||||
PADDLE_ENFORCE_EQ(iter != op_var2gpu_str.end(),
|
||||
true,
|
||||
common::errors::PreconditionNotMet(
|
||||
"op_var=%s should be in the op_var2gpu_str, but "
|
||||
"now can't find it",
|
||||
op_var));
|
||||
gpu_str_ptr = reinterpret_cast<char*>(iter->second->ptr());
|
||||
}
|
||||
}
|
||||
return gpu_str_ptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void PrintStack(const GPUContext& dev_ctx,
|
||||
const DenseTensor& stats,
|
||||
const std::string& op_type,
|
||||
const std::string& var_name,
|
||||
int dev_id) {
|
||||
auto cpu_stats = memory_utils::Alloc(CPUPlace(), sizeof(int64_t) * 3);
|
||||
int64_t* cpu_stats_ptr = reinterpret_cast<int64_t*>(cpu_stats->ptr());
|
||||
memory_utils::Copy(CPUPlace(),
|
||||
cpu_stats_ptr,
|
||||
stats.place(),
|
||||
stats.data(),
|
||||
3 * sizeof(int64_t),
|
||||
dev_ctx.stream());
|
||||
dev_ctx.Wait();
|
||||
if (cpu_stats_ptr[0] > 0 || cpu_stats_ptr[1] > 0) {
|
||||
const std::string debug_info =
|
||||
GetHintString<T>(op_type, var_name, stats.place(), dev_id);
|
||||
funcs::PrintAndThrowError(debug_info.c_str(),
|
||||
cpu_stats_ptr[0],
|
||||
cpu_stats_ptr[1],
|
||||
cpu_stats_ptr[2]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename MT>
|
||||
static void WriteToOutputDir(const GPUContext& dev_ctx,
|
||||
const DenseTensor& tensor,
|
||||
const DenseTensor& stats,
|
||||
const DenseTensor& values,
|
||||
const std::string& op_type,
|
||||
const std::string& var_name,
|
||||
const std::string& output_dir,
|
||||
const int check_nan_inf_level) {
|
||||
// Copy stats and values from GPU to CPU.
|
||||
DenseTensor cpu_stats;
|
||||
cpu_stats.Resize({static_cast<int64_t>(3)});
|
||||
Copy(dev_ctx, stats, CPUPlace(), false, &cpu_stats);
|
||||
|
||||
DenseTensor cpu_values;
|
||||
cpu_values.Resize({static_cast<int64_t>(3)});
|
||||
Copy(dev_ctx, values, CPUPlace(), false, &cpu_values);
|
||||
dev_ctx.Wait();
|
||||
|
||||
int dev_id = tensor.place().device;
|
||||
const std::string debug_info =
|
||||
GetHintString<T>(op_type, var_name, tensor.place(), dev_id);
|
||||
std::string log_name = "gpu." + std::to_string(dev_id);
|
||||
int64_t* cpu_stats_ptr = cpu_stats.data<int64_t>();
|
||||
float* cpu_values_ptr = cpu_values.data<float>();
|
||||
funcs::WriteToFileForDifferentLevel<T, MT>(debug_info.c_str(),
|
||||
tensor.numel(),
|
||||
cpu_stats_ptr[0],
|
||||
cpu_stats_ptr[1],
|
||||
cpu_stats_ptr[2],
|
||||
cpu_values_ptr[0],
|
||||
cpu_values_ptr[1],
|
||||
cpu_values_ptr[2],
|
||||
check_nan_inf_level,
|
||||
log_name,
|
||||
output_dir);
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void CheckNumericsKernel(const Context& dev_ctx,
|
||||
const DenseTensor& tensor,
|
||||
const std::string& op_type,
|
||||
const std::string& var_name,
|
||||
const int check_nan_inf_level,
|
||||
const int stack_height_limit,
|
||||
const std::string& output_dir,
|
||||
DenseTensor* stats,
|
||||
DenseTensor* values) {
|
||||
int dev_id = tensor.place().device;
|
||||
VLOG(6) << "op_type=" << op_type << ", var_name=" << var_name
|
||||
<< ", dev_id=gpu:" << dev_id << ", numel=" << tensor.numel()
|
||||
<< ", stack_height_limit=" << stack_height_limit
|
||||
<< ", output_dir=" << output_dir;
|
||||
|
||||
if (tensor.numel() <= 0) return;
|
||||
|
||||
// Print to the standard output.
|
||||
char* gpu_str_ptr =
|
||||
GetGpuHintStringPtr<T>(dev_ctx, op_type, var_name, dev_id);
|
||||
|
||||
const size_t threads = 1024;
|
||||
size_t blocks =
|
||||
std::min(static_cast<size_t>(128),
|
||||
static_cast<size_t>((tensor.numel() + threads - 1) / threads));
|
||||
|
||||
using MT = typename MPTypeTrait<T>::Type;
|
||||
|
||||
int64_t numel_max_min = blocks;
|
||||
|
||||
DenseTensor block_num_nan_inf_zero;
|
||||
block_num_nan_inf_zero.Resize({static_cast<int64_t>(3 * numel_max_min)});
|
||||
int64_t* block_num_nan_ptr =
|
||||
dev_ctx.template Alloc<int64_t>(&block_num_nan_inf_zero);
|
||||
int64_t* block_num_inf_ptr = block_num_nan_ptr + numel_max_min;
|
||||
int64_t* block_num_zero_ptr = block_num_inf_ptr + numel_max_min;
|
||||
|
||||
DenseTensor tensor_block_max_min;
|
||||
tensor_block_max_min.Resize({static_cast<int64_t>(3 * numel_max_min)});
|
||||
MT* tensor_block_max_ptr = dev_ctx.template Alloc<MT>(&tensor_block_max_min);
|
||||
MT* tensor_block_min_ptr = tensor_block_max_ptr + numel_max_min;
|
||||
MT* tensor_block_mean_ptr = tensor_block_max_ptr + 2 * numel_max_min;
|
||||
|
||||
FindNanInfAndBlockMaxMin<T, MT>
|
||||
<<<blocks, threads, 0, dev_ctx.stream()>>>(tensor.data<T>(),
|
||||
tensor.numel(),
|
||||
block_num_nan_ptr,
|
||||
block_num_inf_ptr,
|
||||
block_num_zero_ptr,
|
||||
tensor_block_max_ptr,
|
||||
tensor_block_min_ptr,
|
||||
tensor_block_mean_ptr);
|
||||
|
||||
// stats stores the checking result of num_nan, num_inf and num_zero.
|
||||
stats->Resize({static_cast<int64_t>(3)});
|
||||
int64_t* stats_ptr = dev_ctx.template Alloc<int64_t>(stats);
|
||||
|
||||
// values stores the max_value, min_value and mean_value.
|
||||
values->Resize({static_cast<int64_t>(3)});
|
||||
float* values_ptr = dev_ctx.template Alloc<float>(values);
|
||||
|
||||
FindGlobalMaxMinAndPrint<T, MT>
|
||||
<<<1, 1, 0, dev_ctx.stream()>>>(block_num_nan_ptr,
|
||||
block_num_inf_ptr,
|
||||
block_num_zero_ptr,
|
||||
tensor_block_max_ptr,
|
||||
tensor_block_min_ptr,
|
||||
tensor_block_mean_ptr,
|
||||
gpu_str_ptr,
|
||||
tensor.numel(),
|
||||
numel_max_min,
|
||||
check_nan_inf_level,
|
||||
stats_ptr,
|
||||
values_ptr);
|
||||
|
||||
if (output_dir.size() > 0) {
|
||||
// Write log to output_dir.
|
||||
WriteToOutputDir<T, MT>(dev_ctx,
|
||||
tensor,
|
||||
*stats,
|
||||
*values,
|
||||
op_type,
|
||||
var_name,
|
||||
output_dir,
|
||||
check_nan_inf_level);
|
||||
}
|
||||
|
||||
if (check_nan_inf_level == 0 && stack_height_limit > 0) {
|
||||
PrintStack<T>(dev_ctx, *stats, op_type, var_name, dev_id);
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
INSTANTIATE_CHECKNUMBERICS_KERNEL(float, GPUContext)
|
||||
INSTANTIATE_CHECKNUMBERICS_KERNEL(double, GPUContext)
|
||||
INSTANTIATE_CHECKNUMBERICS_KERNEL(float16, GPUContext)
|
||||
INSTANTIATE_CHECKNUMBERICS_KERNEL(bfloat16, GPUContext)
|
||||
INSTANTIATE_CHECKNUMBERICS_KERNEL(complex64, GPUContext)
|
||||
INSTANTIATE_CHECKNUMBERICS_KERNEL(complex128, GPUContext)
|
||||
INSTANTIATE_CHECKNUMBERICS_KERNEL(float8_e4m3fn, GPUContext)
|
||||
INSTANTIATE_CHECKNUMBERICS_KERNEL(float8_e5m2, GPUContext)
|
||||
#endif
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(check_numerics,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CheckNumericsKernel,
|
||||
float,
|
||||
double,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128,
|
||||
phi::float8_e4m3fn,
|
||||
phi::float8_e5m2) {}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/cholesky_grad_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/cholesky_grad_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(
|
||||
cholesky_grad, GPU, ALL_LAYOUT, phi::CholeskyGradKernel, float, double) {}
|
||||
@@ -0,0 +1,317 @@
|
||||
/* 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. */
|
||||
|
||||
#ifndef PADDLE_WITH_HIP
|
||||
// HIP not support cusolver
|
||||
|
||||
#include "paddle/phi/kernels/cholesky_kernel.h"
|
||||
|
||||
#include <thrust/device_vector.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/phi/backends/dynload/cusolver.h"
|
||||
#include "paddle/phi/backends/gpu/cuda/cuda_graph_with_memory_pool.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/common/memory_utils.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/for_range.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T>
|
||||
struct MatrixBandPartFunctor {
|
||||
/*! Set output as input value outside a central band and 0 inside that band.
|
||||
* That is: output[i, j, ..., m, n] = in_band(m, n) * input[i, j, ..., m, n]
|
||||
* where: in_band(m, n) = (num_lower < 0 || (m-n) <= num_lower)) && (num_upper
|
||||
* < 0 || (n-m) <= num_upper)
|
||||
*/
|
||||
MatrixBandPartFunctor(const int m,
|
||||
const int n,
|
||||
const int num_lower_diags,
|
||||
const int num_upper_diags,
|
||||
const T* input,
|
||||
T* output)
|
||||
: m_(m),
|
||||
n_(n),
|
||||
num_lower_diags_(num_lower_diags),
|
||||
num_upper_diags_(num_upper_diags),
|
||||
input_(input),
|
||||
output_(output) {}
|
||||
|
||||
HOSTDEVICE void operator()(size_t index) const {
|
||||
const int col = index % n_;
|
||||
const int row = (index / n_) % m_;
|
||||
const int band_start = (num_lower_diags_ < 0 ? 0 : row - num_lower_diags_);
|
||||
const int band_end =
|
||||
(num_upper_diags_ < 0 ? n_ : row + num_upper_diags_ + 1);
|
||||
if (col < band_start || col >= band_end) {
|
||||
output_[index] = static_cast<T>(0);
|
||||
} else {
|
||||
output_[index] = input_[index];
|
||||
}
|
||||
}
|
||||
|
||||
const int m_, n_, num_lower_diags_, num_upper_diags_;
|
||||
const T* input_;
|
||||
T* output_;
|
||||
};
|
||||
|
||||
#define FUNC_WITH_TYPES(m) m(float, S) m(double, D)
|
||||
|
||||
#define POTRF_INSTANCE(T, C) \
|
||||
void Potrf(const GPUContext& dev_ctx, \
|
||||
cublasFillMode_t uplo, \
|
||||
int n, \
|
||||
T* A, \
|
||||
int lda, \
|
||||
int* info) { \
|
||||
auto handle = dev_ctx.cusolver_dn_handle(); \
|
||||
int workspace_size = 0; \
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(dynload::cusolverDn##C##potrf_bufferSize( \
|
||||
handle, uplo, n, A, lda, &workspace_size)); \
|
||||
auto workspace = memory_utils::Alloc( \
|
||||
dev_ctx.GetPlace(), \
|
||||
workspace_size * sizeof(T), \
|
||||
Stream(reinterpret_cast<StreamId>(dev_ctx.stream()))); \
|
||||
T* workspace_ptr = reinterpret_cast<T*>(workspace->ptr()); \
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(dynload::cusolverDn##C##potrf( \
|
||||
handle, uplo, n, A, lda, workspace_ptr, workspace_size, info)); \
|
||||
}
|
||||
|
||||
FUNC_WITH_TYPES(POTRF_INSTANCE);
|
||||
|
||||
#if CUDA_VERSION >= 11040
|
||||
#define POTRF64_INSTANCE(T, C) \
|
||||
void Potrf64(const GPUContext& dev_ctx, \
|
||||
cublasFillMode_t uplo, \
|
||||
int64_t n, \
|
||||
T* A, \
|
||||
int64_t lda, \
|
||||
int* info) { \
|
||||
auto handle = dev_ctx.cusolver_dn_handle(); \
|
||||
cusolverDnParams_t params; \
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(dynload::cusolverDnCreateParams(¶ms)); \
|
||||
size_t workspace_device_size = 0; \
|
||||
size_t workspace_host_size = 0; \
|
||||
cudaDataType_t data_type = \
|
||||
std::is_same<T, float>::value ? CUDA_R_32F : CUDA_R_64F; \
|
||||
PADDLE_ENFORCE_GPU_SUCCESS( \
|
||||
dynload::cusolverDnXpotrf_bufferSize(handle, \
|
||||
params, \
|
||||
uplo, \
|
||||
n, \
|
||||
data_type, \
|
||||
A, \
|
||||
lda, \
|
||||
data_type, \
|
||||
&workspace_device_size, \
|
||||
&workspace_host_size)); \
|
||||
auto workspace_device = memory_utils::Alloc( \
|
||||
dev_ctx.GetPlace(), \
|
||||
workspace_device_size, \
|
||||
Stream(reinterpret_cast<StreamId>(dev_ctx.stream()))); \
|
||||
auto workspace_host = \
|
||||
memory_utils::Alloc(CPUPlace(), workspace_host_size); \
|
||||
PADDLE_ENFORCE_GPU_SUCCESS( \
|
||||
dynload::cusolverDnXpotrf(handle, \
|
||||
params, \
|
||||
uplo, \
|
||||
n, \
|
||||
data_type, \
|
||||
A, \
|
||||
lda, \
|
||||
data_type, \
|
||||
workspace_device->ptr(), \
|
||||
workspace_device_size, \
|
||||
workspace_host->ptr(), \
|
||||
workspace_host_size, \
|
||||
info)); \
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(dynload::cusolverDnDestroyParams(params)); \
|
||||
}
|
||||
|
||||
FUNC_WITH_TYPES(POTRF64_INSTANCE);
|
||||
#endif
|
||||
|
||||
#if CUDA_VERSION >= 9020 && !defined(_WIN32)
|
||||
#define POTRF_BATCH_INSTANCE(T, C) \
|
||||
void PotrfBatched(const GPUContext& dev_ctx, \
|
||||
cublasFillMode_t uplo, \
|
||||
int n, \
|
||||
T* Aarray[], \
|
||||
int lda, \
|
||||
int* info_array, \
|
||||
int batch_size) { \
|
||||
auto handle = dev_ctx.cusolver_dn_handle(); \
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(dynload::cusolverDn##C##potrfBatched( \
|
||||
handle, uplo, n, Aarray, lda, info_array, batch_size)); \
|
||||
}
|
||||
|
||||
FUNC_WITH_TYPES(POTRF_BATCH_INSTANCE);
|
||||
#endif
|
||||
|
||||
template <typename T, typename Context>
|
||||
void CholeskyKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
bool upper,
|
||||
DenseTensor* out) {
|
||||
if (x.numel() == 0) {
|
||||
dev_ctx.template Alloc<T>(out);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& dims = x.dims();
|
||||
int64_t batch_count64 = 1;
|
||||
for (int i = 0; i < dims.size() - 2; i++) {
|
||||
batch_count64 *= dims[i];
|
||||
}
|
||||
// TODO(large-tensor): cusolver batch_count not support int64
|
||||
PADDLE_ENFORCE_LE_INT_MAX(batch_count64, "batch_count");
|
||||
int batch_count = static_cast<int>(batch_count64);
|
||||
|
||||
int64_t m = dims[dims.size() - 1];
|
||||
// TODO(large-tensor): cusolver n not support int64
|
||||
PADDLE_ENFORCE_LE_INT_MAX(m, "m");
|
||||
int m_int = static_cast<int>(m);
|
||||
|
||||
int64_t tensor_size = batch_count * static_cast<int64_t>(m) * m;
|
||||
|
||||
const auto* x_data = x.data<T>();
|
||||
auto* out_data = dev_ctx.template Alloc<T>(out);
|
||||
|
||||
// matrices are assumed to be stored in column-major order in cusolver
|
||||
cublasFillMode_t uplo =
|
||||
upper ? CUBLAS_FILL_MODE_LOWER : CUBLAS_FILL_MODE_UPPER;
|
||||
// portf is inplace, thus copy the triangular part of the input matrices to
|
||||
// the output and set the other triangular part to 0 firstly
|
||||
|
||||
funcs::ForRange<GPUContext> for_range(dev_ctx, tensor_size);
|
||||
// Pre-processing
|
||||
if (upper) {
|
||||
MatrixBandPartFunctor<T> matrix_band_part_functor(
|
||||
m, m, 0, -1, x_data, out_data);
|
||||
for_range(matrix_band_part_functor);
|
||||
} else {
|
||||
MatrixBandPartFunctor<T> matrix_band_part_functor(
|
||||
m, m, -1, 0, x_data, out_data);
|
||||
for_range(matrix_band_part_functor);
|
||||
}
|
||||
|
||||
auto info =
|
||||
memory_utils::Alloc(dev_ctx.GetPlace(),
|
||||
sizeof(int) * batch_count,
|
||||
Stream(reinterpret_cast<StreamId>(dev_ctx.stream())));
|
||||
auto* info_ptr = reinterpret_cast<int*>(info->ptr());
|
||||
|
||||
#if CUDA_VERSION >= 9020 && !defined(_WIN32)
|
||||
if (batch_count > 1) {
|
||||
std::vector<T*> output_ptrs;
|
||||
for (int i = 0; i < batch_count; i++) {
|
||||
output_ptrs.emplace_back(out_data + static_cast<int64_t>(i) * m * m);
|
||||
}
|
||||
thrust::device_vector<T*> dev_output_ptrs(output_ptrs.begin(),
|
||||
output_ptrs.end());
|
||||
PotrfBatched(dev_ctx,
|
||||
uplo,
|
||||
m_int,
|
||||
thrust::raw_pointer_cast(dev_output_ptrs.data()),
|
||||
m_int,
|
||||
info_ptr,
|
||||
batch_count);
|
||||
// TODO(guosheng): There seems to a bug in cusolver potrfBatched and need
|
||||
// to clear the upper triangle of the output. Remove this workaround once
|
||||
// the bug is fixed.
|
||||
|
||||
if (!upper) {
|
||||
MatrixBandPartFunctor<T> matrix_band_part_functor(
|
||||
m, m, -1, 0, out_data, out_data);
|
||||
for_range(matrix_band_part_functor);
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
for (int i = 0; i < batch_count; i++) {
|
||||
int64_t offset = static_cast<int64_t>(i) * m * m;
|
||||
#if CUDA_VERSION >= 11040
|
||||
Potrf64(dev_ctx, uplo, m_int, out_data + offset, m_int, info_ptr + i);
|
||||
#else
|
||||
Potrf(dev_ctx, uplo, m_int, out_data + offset, m_int, info_ptr + i);
|
||||
#endif
|
||||
}
|
||||
#if CUDA_VERSION >= 9020 && !defined(_WIN32)
|
||||
}
|
||||
#endif
|
||||
// check the info
|
||||
PADDLE_ENFORCE_EQ(
|
||||
backends::gpu::IsCUDAGraphCapturing(),
|
||||
false,
|
||||
common::errors::InvalidArgument(
|
||||
"CholeskyKernel does not support CUDA Graph capture: async D2H copy "
|
||||
"to local vector 'error_info' will bake the destination address into "
|
||||
"the graph; on replay the vector is re-created at a different "
|
||||
"address, causing a dangling-pointer write."));
|
||||
std::vector<int> error_info;
|
||||
error_info.resize(batch_count);
|
||||
memory_utils::Copy(CPUPlace(),
|
||||
error_info.data(),
|
||||
dev_ctx.GetPlace(),
|
||||
info_ptr,
|
||||
sizeof(int) * batch_count,
|
||||
dev_ctx.stream());
|
||||
|
||||
for (int i = 0; i < batch_count; ++i) {
|
||||
const int info = error_info[i];
|
||||
if (info == 0) {
|
||||
continue;
|
||||
}
|
||||
if (info < 0) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
info,
|
||||
0,
|
||||
errors::InvalidArgument("Cholesky kernel failed for batch %d: "
|
||||
"The %d-th argument was invalid, please "
|
||||
"check the kernel implementation.",
|
||||
i,
|
||||
-info));
|
||||
}
|
||||
PADDLE_ENFORCE_EQ(
|
||||
info,
|
||||
0,
|
||||
errors::PreconditionNotMet(
|
||||
"Cholesky decomposition failed for batch %d: "
|
||||
"The leading minor of order %d is not positive definite.",
|
||||
i,
|
||||
info));
|
||||
}
|
||||
|
||||
// Post-processing to clear the other triangle
|
||||
if (upper) {
|
||||
MatrixBandPartFunctor<T> band_part_post(m, m, 0, -1, out_data, out_data);
|
||||
for_range(band_part_post);
|
||||
} else {
|
||||
MatrixBandPartFunctor<T> band_part_post(m, m, -1, 0, out_data, out_data);
|
||||
for_range(band_part_post);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(cholesky, // cuda_only
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CholeskyKernel,
|
||||
float,
|
||||
double) {}
|
||||
|
||||
#endif // not PADDLE_WITH_HIP
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/cholesky_solve_grad_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(cholesky_solve_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::CholeskySolveGradKernel,
|
||||
float,
|
||||
double) {}
|
||||
@@ -0,0 +1,181 @@
|
||||
// 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.
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
#include "paddle/phi/backends/dynload/rocsolver.h"
|
||||
#else
|
||||
#include "paddle/phi/backends/dynload/cusolver.h"
|
||||
#endif
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/enforce.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/lapack/lapack_function.h"
|
||||
#include "paddle/phi/kernels/impl/cholesky_solve_kernel_impl.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
template <typename T>
|
||||
void rocsolver_potrs(const solverHandle_t &handle,
|
||||
rocblas_fill uplo,
|
||||
int M,
|
||||
int N,
|
||||
T *Adata,
|
||||
int lda,
|
||||
T *Bdata,
|
||||
int ldb);
|
||||
|
||||
using dtype::complex;
|
||||
#define FUNC_WITH_TYPES(m) \
|
||||
m(float, s, float) m(double, d, double) \
|
||||
m(complex<float>, c, rocblas_float_complex) \
|
||||
m(complex<double>, z, rocblas_double_complex)
|
||||
|
||||
#define POTRS_INSTANCE(T, C, CastType) \
|
||||
template <> \
|
||||
void rocsolver_potrs<T>(const solverHandle_t &handle, \
|
||||
rocblas_fill uplo, \
|
||||
int M, \
|
||||
int N, \
|
||||
T *Adata, \
|
||||
int lda, \
|
||||
T *Bdata, \
|
||||
int ldb) { \
|
||||
PADDLE_ENFORCE_GPU_SUCCESS( \
|
||||
dynload::rocsolver_##C##potrs(handle, \
|
||||
uplo, \
|
||||
M, \
|
||||
N, \
|
||||
reinterpret_cast<CastType *>(Adata), \
|
||||
lda, \
|
||||
reinterpret_cast<CastType *>(Bdata), \
|
||||
ldb)); \
|
||||
}
|
||||
|
||||
FUNC_WITH_TYPES(POTRS_INSTANCE);
|
||||
|
||||
#else
|
||||
template <typename T>
|
||||
void cusolver_potrs(const solverHandle_t &handle,
|
||||
cublasFillMode_t uplo,
|
||||
int M,
|
||||
int N,
|
||||
T *Adata,
|
||||
int lda,
|
||||
T *Bdata,
|
||||
int ldb,
|
||||
int *devInfo);
|
||||
|
||||
template <>
|
||||
void cusolver_potrs<float>(const solverHandle_t &handle,
|
||||
cublasFillMode_t uplo,
|
||||
int M,
|
||||
int N,
|
||||
float *Adata,
|
||||
int lda,
|
||||
float *Bdata,
|
||||
int ldb,
|
||||
int *devInfo) {
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(dynload::cusolverDnSpotrs(
|
||||
handle, uplo, M, N, Adata, lda, Bdata, ldb, devInfo));
|
||||
}
|
||||
|
||||
template <>
|
||||
void cusolver_potrs<double>(const solverHandle_t &handle,
|
||||
cublasFillMode_t uplo,
|
||||
int M,
|
||||
int N,
|
||||
double *Adata,
|
||||
int lda,
|
||||
double *Bdata,
|
||||
int ldb,
|
||||
int *devInfo) {
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(dynload::cusolverDnDpotrs(
|
||||
handle, uplo, M, N, Adata, lda, Bdata, ldb, devInfo));
|
||||
}
|
||||
|
||||
template <>
|
||||
void cusolver_potrs<complex64>(const solverHandle_t &handle,
|
||||
cublasFillMode_t uplo,
|
||||
int M,
|
||||
int N,
|
||||
complex64 *Adata,
|
||||
int lda,
|
||||
complex64 *Bdata,
|
||||
int ldb,
|
||||
int *devInfo) {
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(
|
||||
dynload::cusolverDnCpotrs(handle,
|
||||
uplo,
|
||||
M,
|
||||
N,
|
||||
reinterpret_cast<const cuComplex *>(Adata),
|
||||
lda,
|
||||
reinterpret_cast<cuComplex *>(Bdata),
|
||||
ldb,
|
||||
devInfo));
|
||||
}
|
||||
|
||||
template <>
|
||||
void cusolver_potrs<complex128>(const cusolverDnHandle_t &handle,
|
||||
cublasFillMode_t uplo,
|
||||
int M,
|
||||
int N,
|
||||
complex128 *Adata,
|
||||
int lda,
|
||||
complex128 *Bdata,
|
||||
int ldb,
|
||||
int *devInfo) {
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(dynload::cusolverDnZpotrs(
|
||||
handle,
|
||||
uplo,
|
||||
M,
|
||||
N,
|
||||
reinterpret_cast<const cuDoubleComplex *>(Adata),
|
||||
lda,
|
||||
reinterpret_cast<cuDoubleComplex *>(Bdata),
|
||||
ldb,
|
||||
devInfo));
|
||||
}
|
||||
|
||||
#endif // PADDLE_WITH_HIP
|
||||
|
||||
template <typename T>
|
||||
class CholeskySolveFunctor<T, GPUContext> {
|
||||
public:
|
||||
void operator()(const GPUContext &dev_ctx,
|
||||
bool upper,
|
||||
int M,
|
||||
int N,
|
||||
T *Adata,
|
||||
int lda,
|
||||
T *Bdata,
|
||||
int *devInfo) {
|
||||
auto handle = dev_ctx.cusolver_dn_handle();
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
rocblas_fill uplo = upper ? rocblas_fill_upper : rocblas_fill_lower;
|
||||
rocsolver_potrs<T>(handle, uplo, M, N, Adata, lda, Bdata, lda);
|
||||
#else
|
||||
cublasFillMode_t uplo =
|
||||
upper ? CUBLAS_FILL_MODE_UPPER : CUBLAS_FILL_MODE_LOWER;
|
||||
cusolver_potrs<T>(handle, uplo, M, N, Adata, lda, Bdata, lda, devInfo);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(
|
||||
cholesky_solve, GPU, ALL_LAYOUT, phi::CholeskySolveKernel, float, double) {}
|
||||
@@ -0,0 +1,586 @@
|
||||
// Copyright (c) 2024 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.
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
#include <hiprand.h>
|
||||
#include <hiprand_kernel.h>
|
||||
typedef hiprandState curandState;
|
||||
#else
|
||||
#include <curand.h>
|
||||
#include <curand_kernel.h>
|
||||
#endif
|
||||
|
||||
#include <iterator>
|
||||
#include <random>
|
||||
#include "paddle/phi/common/memory_utils.h"
|
||||
#include "paddle/phi/core/enforce.h"
|
||||
#include "paddle/phi/core/tensor_utils.h"
|
||||
#include "paddle/phi/kernels/class_center_sample_kernel.h"
|
||||
#include "paddle/phi/kernels/funcs/cub.h"
|
||||
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
#include "paddle/common/flags.h"
|
||||
#include "paddle/phi/core/distributed/nccl_comm_context.h"
|
||||
#endif
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
|
||||
namespace phi {
|
||||
#define CUDA_KERNEL_LOOP_TYPE(i, n, index_type) \
|
||||
for (index_type i = blockIdx.x * blockDim.x + threadIdx.x, \
|
||||
step = blockDim.x * gridDim.x; \
|
||||
i < (n); \
|
||||
i += step)
|
||||
|
||||
#define CUDA_KERNEL_LOOP(i, n) CUDA_KERNEL_LOOP_TYPE(i, n, int32_t)
|
||||
|
||||
static constexpr int kNumCUDAThreads = 512;
|
||||
static constexpr int kNumMaximumNumBlocks = 4096;
|
||||
|
||||
inline int32_t NumBlocks(const int32_t n) {
|
||||
return std::min((n + kNumCUDAThreads - 1) / kNumCUDAThreads,
|
||||
kNumMaximumNumBlocks);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void RandomSampleClassCenter(const int64_t n,
|
||||
int64_t seed,
|
||||
int64_t increment,
|
||||
const int64_t max_val,
|
||||
T* buffer) {
|
||||
const int id = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
curandState localState;
|
||||
size_t local_seed =
|
||||
(static_cast<size_t>(seed) + 0x9E3779B9U +
|
||||
(static_cast<size_t>(id) << 6U) + (static_cast<size_t>(id) >> 2U));
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hiprand_init(local_seed, id, increment, &localState);
|
||||
CUDA_KERNEL_LOOP(i, n) {
|
||||
buffer[i] = static_cast<T>(hiprand(&localState) % max_val);
|
||||
}
|
||||
#else
|
||||
curand_init(local_seed, id, increment, &localState);
|
||||
CUDA_KERNEL_LOOP(i, n) {
|
||||
buffer[i] = static_cast<T>(curand(&localState) % max_val);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void Range(const int64_t n, T* out) {
|
||||
CUDA_KERNEL_LOOP(i, n) { out[i] = static_cast<T>(i); }
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void MarkPositiveClassCenter(const int64_t n,
|
||||
const int64_t rank,
|
||||
const T* class_interval_ptr,
|
||||
const int num_classes,
|
||||
const T* labels,
|
||||
T* out) {
|
||||
CUDA_KERNEL_LOOP(i, n) {
|
||||
T label = labels[i] - class_interval_ptr[rank];
|
||||
if (label >= 0 && label < num_classes) {
|
||||
out[label] = label - num_classes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__device__ void FindIntervalIndex(const T* class_interval_ptr,
|
||||
const int64_t nranks,
|
||||
const T value,
|
||||
int64_t* find_index) {
|
||||
int64_t start = 0;
|
||||
int64_t end = nranks;
|
||||
int64_t mid = ((end - start) >> 1) + start + 1;
|
||||
while (start < end) {
|
||||
if (class_interval_ptr[mid] == value) break;
|
||||
if (class_interval_ptr[mid] > value)
|
||||
end = mid - 1;
|
||||
else
|
||||
start = mid;
|
||||
mid = ((end - start) >> 1) + start + 1;
|
||||
}
|
||||
*find_index = min(mid, end);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void GetClassCenterBound(const int64_t n,
|
||||
const int64_t nranks,
|
||||
const T* class_interval_ptr,
|
||||
const T* key_ptr,
|
||||
const T* value_ptr,
|
||||
T* bound_index,
|
||||
T* bound_value) {
|
||||
CUDA_KERNEL_LOOP(i, n) {
|
||||
if (i != 0) {
|
||||
int64_t cur_index, pre_index;
|
||||
FindIntervalIndex(class_interval_ptr, nranks, key_ptr[i], &cur_index);
|
||||
FindIntervalIndex(class_interval_ptr, nranks, key_ptr[i - 1], &pre_index);
|
||||
if (cur_index > pre_index) {
|
||||
assert(cur_index < nranks);
|
||||
#pragma unroll
|
||||
for (int32_t j = pre_index + 1; j <= cur_index; ++j) {
|
||||
bound_index[j] = static_cast<T>(i);
|
||||
bound_value[j] = value_ptr[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CUDA_KERNEL_LOOP(i, nranks + 1) {
|
||||
int64_t first_index, last_index;
|
||||
FindIntervalIndex(class_interval_ptr, nranks, key_ptr[0], &first_index);
|
||||
FindIntervalIndex(class_interval_ptr, nranks, key_ptr[n - 1], &last_index);
|
||||
if (i <= first_index) {
|
||||
bound_index[i] = 0;
|
||||
bound_value[i] = value_ptr[0];
|
||||
} else if (i > last_index) {
|
||||
bound_index[i] = n;
|
||||
bound_value[i] = value_ptr[n - 1] + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void GetRemappedLabel(const int64_t n,
|
||||
const int64_t nranks,
|
||||
const T* sampled_class_interval_ptr,
|
||||
const T* bound_index,
|
||||
const T* bound_value,
|
||||
const T* label_map_key,
|
||||
T* label_map_value,
|
||||
T* mapped_label) {
|
||||
CUDA_KERNEL_LOOP(i, n) {
|
||||
#pragma unroll
|
||||
for (int64_t j = 0; j < nranks; j++) {
|
||||
if (i >= bound_index[j] && i < bound_index[j + 1]) {
|
||||
label_map_value[i] =
|
||||
label_map_value[i] - bound_value[j] + sampled_class_interval_ptr[j];
|
||||
}
|
||||
}
|
||||
mapped_label[label_map_key[i]] = label_map_value[i];
|
||||
}
|
||||
}
|
||||
|
||||
// aligned vector generates vectorized load/store on CUDA
|
||||
template <typename T, int Size>
|
||||
struct alignas(sizeof(T) * Size) AlignedVector {
|
||||
T val[Size];
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline int VectorizedSize(const T* pointer) {
|
||||
uint64_t address = reinterpret_cast<uint64_t>(pointer);
|
||||
constexpr int vec4 = std::alignment_of<AlignedVector<T, 4>>::value; // NOLINT
|
||||
if (address % vec4 == 0) {
|
||||
return 4;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#undef CUDA_KERNEL_LOOP
|
||||
|
||||
template <typename T>
|
||||
class NotEqualToPreviousAdjacentIterator {
|
||||
public:
|
||||
using self_type = NotEqualToPreviousAdjacentIterator;
|
||||
using value_type = T;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = T*;
|
||||
using reference = T;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
public:
|
||||
__host__ __device__ __forceinline__
|
||||
NotEqualToPreviousAdjacentIterator(const T* arr, int64_t offset)
|
||||
: arr_(arr), offset_(offset) {}
|
||||
|
||||
__host__ __device__ __forceinline__ reference operator*() const {
|
||||
return offset_ == 0 ? 0 : (arr_[offset_] == arr_[offset_ - 1] ? 0 : 1);
|
||||
}
|
||||
|
||||
template <typename Distance>
|
||||
__host__ __device__ __forceinline__ self_type operator+(Distance n) const {
|
||||
self_type ret(arr_, offset_ + n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Distance>
|
||||
__host__ __device__ __forceinline__ self_type operator-(Distance n) const {
|
||||
self_type ret(arr_, offset_ - n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Distance>
|
||||
__host__ __device__ __forceinline__ reference operator[](Distance n) const {
|
||||
return *(*this + n);
|
||||
}
|
||||
|
||||
private:
|
||||
const T* arr_;
|
||||
int64_t offset_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ActualNumSampledFunctor {
|
||||
__host__ __device__ __forceinline__ T operator()(const T& a,
|
||||
const T& b) const {
|
||||
return max(num_samples, (b - a));
|
||||
}
|
||||
T num_samples;
|
||||
explicit ActualNumSampledFunctor(const T num) : num_samples(num) {}
|
||||
};
|
||||
|
||||
template <typename T, typename Context>
|
||||
class MemoryBuffer {
|
||||
public:
|
||||
MemoryBuffer(const int num_buffer_ele,
|
||||
const int num_temp_ele,
|
||||
const int nranks,
|
||||
const Context& dev_ctx) {
|
||||
offset1 = 0;
|
||||
offset2 = offset1 + num_buffer_ele;
|
||||
offset3 = offset2 + num_buffer_ele;
|
||||
offset4 = offset3 + num_buffer_ele;
|
||||
offset5 = offset4 + num_buffer_ele;
|
||||
offset6 = offset5 + (nranks + 1);
|
||||
offset7 = offset6 + (nranks + 1);
|
||||
offset8 = offset7 + (nranks + 1);
|
||||
offset9 = offset8 + num_temp_ele;
|
||||
|
||||
buffer.Resize({4 * num_buffer_ele + 3 * (nranks + 1) + num_temp_ele});
|
||||
buffer_ptr = dev_ctx.template Alloc<T>(&buffer);
|
||||
}
|
||||
|
||||
T* cub_sort_keys_ptr() { return buffer_ptr + offset1; }
|
||||
T* cub_sort_keys_out_ptr() { return buffer_ptr + offset2; }
|
||||
T* cub_sort_values_ptr() { return buffer_ptr + offset3; }
|
||||
T* cub_sort_values_out_ptr() { return buffer_ptr + offset4; }
|
||||
T* bound_index_ptr() { return buffer_ptr + offset5; }
|
||||
T* bound_value_ptr() { return buffer_ptr + offset6; }
|
||||
T* class_interval_ptr() { return buffer_ptr + offset7; }
|
||||
void* cub_temp_storage_ptr() {
|
||||
return reinterpret_cast<void*>(buffer_ptr + offset8);
|
||||
}
|
||||
|
||||
private:
|
||||
DenseTensor buffer;
|
||||
T* buffer_ptr;
|
||||
int offset1;
|
||||
int offset2;
|
||||
int offset3;
|
||||
int offset4;
|
||||
int offset5;
|
||||
int offset6;
|
||||
int offset7;
|
||||
int offset8;
|
||||
int offset9;
|
||||
};
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ClassCenterSampleKernel(const Context& dev_ctx,
|
||||
const DenseTensor& label,
|
||||
int num_classes,
|
||||
int num_samples,
|
||||
int ring_id,
|
||||
int rank,
|
||||
int nranks,
|
||||
bool fix_seed,
|
||||
int seed,
|
||||
DenseTensor* remapped_label,
|
||||
DenseTensor* sampled_local_class_center) {
|
||||
PADDLE_ENFORCE_GT(num_classes,
|
||||
0,
|
||||
errors::InvalidArgument(
|
||||
"The value 'num_classes' for Op(class_center_sample) "
|
||||
"must be greater than 0, "
|
||||
"but the value given is %d.",
|
||||
num_classes));
|
||||
|
||||
PADDLE_ENFORCE_GT(num_samples,
|
||||
0,
|
||||
errors::InvalidArgument(
|
||||
"The value 'num_samples' for Op(class_center_sample) "
|
||||
"must be greater than 0, "
|
||||
"but the value given is %d.",
|
||||
num_samples));
|
||||
|
||||
PADDLE_ENFORCE_LE(num_samples,
|
||||
num_classes,
|
||||
errors::InvalidArgument(
|
||||
"The value 'num_samples' for Op(class_center_sample) "
|
||||
"must be less than or equal to %d, "
|
||||
"but the value given is %d.",
|
||||
num_classes,
|
||||
num_samples));
|
||||
|
||||
auto place = dev_ctx.GetPlace();
|
||||
|
||||
int64_t batch_size = label.numel();
|
||||
// TODO(large-tensor): downstream functors may still use int
|
||||
PADDLE_ENFORCE_LE_INT_MAX(label.numel(), "label.numel()");
|
||||
// Algorithm:
|
||||
// We first randomly generate a value in [0, num_classes) on each position
|
||||
// in a array(shape[num_classes]). Then, we mark the element as negative
|
||||
// value in the array according input label. Now, we can sort the array
|
||||
// by ascending to ensure that the positive class center always in the
|
||||
// front of the sorted array. So, we can get the sampled class center
|
||||
// index by sorted keys. Finally, we can get the rempped label by remap
|
||||
// the input label according sampled class center.
|
||||
|
||||
// step 1: Calculate num classes per device using nccl all reduce
|
||||
std::vector<T> shard_dim_vec(nranks + 1, 0);
|
||||
shard_dim_vec[rank + 1] = num_classes;
|
||||
DenseTensor num_classes_per_device;
|
||||
TensorFromVector(shard_dim_vec, dev_ctx, &num_classes_per_device);
|
||||
T* num_classes_per_device_ptr = num_classes_per_device.data<T>();
|
||||
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
if (nranks > 1) {
|
||||
auto stream = dev_ctx.stream();
|
||||
distributed::NCCLCommContext* comm_ctx = nullptr;
|
||||
comm_ctx =
|
||||
static_cast<distributed::NCCLCommContext*>(dev_ctx.GetCommContext());
|
||||
PADDLE_ENFORCE_NE(comm_ctx,
|
||||
nullptr,
|
||||
common::errors::Unavailable(
|
||||
"NCCLCommContext is nullptr, collective op should "
|
||||
"has ring_id attr."));
|
||||
|
||||
comm_ctx->AllReduce(
|
||||
&num_classes_per_device, num_classes_per_device, ncclSum, stream);
|
||||
backends::gpu::GpuStreamSync(stream);
|
||||
}
|
||||
#endif
|
||||
|
||||
// step 2: Determine temporary device storage requirements
|
||||
int num_buffer_ele = std::max(static_cast<int>(batch_size), num_classes);
|
||||
size_t cub_sort_temp_store_size = 0;
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(
|
||||
(cub::DeviceRadixSort::SortPairs<T, T>(nullptr,
|
||||
cub_sort_temp_store_size,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
num_buffer_ele,
|
||||
0,
|
||||
sizeof(T) * 8,
|
||||
dev_ctx.stream())));
|
||||
|
||||
size_t cub_sum_temp_store_size = 0;
|
||||
NotEqualToPreviousAdjacentIterator<T> unique_counting_iter_temp(nullptr, 0);
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(
|
||||
(cub::DeviceScan::InclusiveSum<NotEqualToPreviousAdjacentIterator<T>, T*>(
|
||||
nullptr,
|
||||
cub_sum_temp_store_size,
|
||||
unique_counting_iter_temp,
|
||||
nullptr,
|
||||
batch_size,
|
||||
dev_ctx.stream())));
|
||||
|
||||
size_t cub_scan_temp_store_size = 0;
|
||||
ActualNumSampledFunctor<T> actual_num_sampled_op_temp(num_samples);
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(
|
||||
(cub::DeviceScan::InclusiveScan(nullptr,
|
||||
cub_scan_temp_store_size,
|
||||
num_classes_per_device_ptr,
|
||||
num_classes_per_device_ptr,
|
||||
actual_num_sampled_op_temp,
|
||||
nranks + 1,
|
||||
dev_ctx.stream())));
|
||||
|
||||
size_t cub_temp_storage_bytes =
|
||||
std::max(std::max(cub_sort_temp_store_size, cub_scan_temp_store_size),
|
||||
cub_sum_temp_store_size);
|
||||
int num_temp_ele = cub_temp_storage_bytes / sizeof(T) + 1;
|
||||
PADDLE_ENFORCE_GT(
|
||||
(4 * num_buffer_ele + 3 * (nranks + 1) + num_temp_ele),
|
||||
0,
|
||||
errors::InvalidArgument(
|
||||
"Illegal memory allocation, total allocated space must be greater "
|
||||
"than 0, "
|
||||
"but received %d."
|
||||
"This is mainly caused by the size of 'label' being too large.",
|
||||
(4 * num_buffer_ele + 3 * (nranks + 1) + num_temp_ele)));
|
||||
|
||||
// step 3: Alloc buffer memory so that we can reuse allocated memory
|
||||
MemoryBuffer<T, Context> memory_buffer =
|
||||
MemoryBuffer<T, Context>(num_buffer_ele, num_temp_ele, nranks, dev_ctx);
|
||||
|
||||
T* cub_sort_keys_ptr = memory_buffer.cub_sort_keys_ptr();
|
||||
T* cub_sort_keys_out_ptr = memory_buffer.cub_sort_keys_out_ptr();
|
||||
T* cub_sort_values_ptr = memory_buffer.cub_sort_values_ptr();
|
||||
T* cub_sort_values_out_ptr = memory_buffer.cub_sort_values_out_ptr();
|
||||
T* bound_index_ptr = memory_buffer.bound_index_ptr();
|
||||
T* bound_value_ptr = memory_buffer.bound_value_ptr();
|
||||
T* class_interval_ptr = memory_buffer.class_interval_ptr();
|
||||
void* cub_temp_storage_ptr = memory_buffer.cub_temp_storage_ptr();
|
||||
|
||||
// step 4: Calculate class interval among nranks
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(
|
||||
(cub::DeviceScan::InclusiveSum(cub_temp_storage_ptr,
|
||||
cub_temp_storage_bytes,
|
||||
num_classes_per_device_ptr,
|
||||
class_interval_ptr,
|
||||
nranks + 1,
|
||||
dev_ctx.stream())));
|
||||
|
||||
// step 5: random sample negative class center
|
||||
uint64_t seed_data;
|
||||
uint64_t increment;
|
||||
int vec_size = VectorizedSize<T>(cub_sort_keys_ptr);
|
||||
auto offset = ((num_classes - 1) /
|
||||
(NumBlocks(num_classes) * kNumCUDAThreads * vec_size) +
|
||||
1) *
|
||||
vec_size;
|
||||
// auto gen_cuda = DefaultCUDAGenerator(device_id);
|
||||
auto gen_cuda = dev_ctx.GetGenerator();
|
||||
if (!fix_seed) {
|
||||
auto seed_offset = gen_cuda->IncrementOffset(offset);
|
||||
seed_data = seed_offset.first;
|
||||
increment = seed_offset.second;
|
||||
} else {
|
||||
seed_data = seed + rank;
|
||||
increment = offset;
|
||||
}
|
||||
RandomSampleClassCenter<T>
|
||||
<<<NumBlocks(num_classes), kNumCUDAThreads, 0, dev_ctx.stream()>>>(
|
||||
num_classes, seed_data, increment, num_classes, cub_sort_keys_ptr);
|
||||
|
||||
// step 6: mark positive class center as negative value
|
||||
// fill the sort values to index 0, 1, ..., batch_size-1
|
||||
MarkPositiveClassCenter<T>
|
||||
<<<NumBlocks(batch_size), kNumCUDAThreads, 0, dev_ctx.stream()>>>(
|
||||
batch_size,
|
||||
rank,
|
||||
class_interval_ptr,
|
||||
num_classes,
|
||||
label.data<T>(),
|
||||
cub_sort_keys_ptr);
|
||||
Range<T><<<NumBlocks(num_buffer_ele), kNumCUDAThreads, 0, dev_ctx.stream()>>>(
|
||||
num_buffer_ele, cub_sort_values_ptr);
|
||||
|
||||
// step 7: sort class center by ascending, so that positive class center
|
||||
// always be sampled.
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(
|
||||
(cub::DeviceRadixSort::SortPairs<T, T>(cub_temp_storage_ptr,
|
||||
cub_temp_storage_bytes,
|
||||
cub_sort_keys_ptr,
|
||||
cub_sort_keys_out_ptr,
|
||||
cub_sort_values_ptr,
|
||||
cub_sort_values_out_ptr,
|
||||
num_classes,
|
||||
0,
|
||||
sizeof(T) * 8,
|
||||
dev_ctx.stream())));
|
||||
|
||||
// step 8: sort input label ascending
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(
|
||||
(cub::DeviceRadixSort::SortPairs<T, T>(cub_temp_storage_ptr,
|
||||
cub_temp_storage_bytes,
|
||||
label.data<T>(),
|
||||
cub_sort_keys_out_ptr,
|
||||
cub_sort_values_ptr,
|
||||
cub_sort_keys_ptr,
|
||||
batch_size,
|
||||
0,
|
||||
sizeof(T) * 8,
|
||||
dev_ctx.stream())));
|
||||
|
||||
// step 9: Calculate new index using InclusiveSum on ascending sorted input
|
||||
// label
|
||||
NotEqualToPreviousAdjacentIterator<T> unique_counting_iter(
|
||||
cub_sort_keys_out_ptr, 0);
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(
|
||||
(cub::DeviceScan::InclusiveSum<NotEqualToPreviousAdjacentIterator<T>, T*>(
|
||||
cub_temp_storage_ptr,
|
||||
cub_temp_storage_bytes,
|
||||
unique_counting_iter,
|
||||
cub_sort_values_ptr,
|
||||
batch_size,
|
||||
dev_ctx.stream())));
|
||||
|
||||
// step 10: Calculate new class center bound among ranks
|
||||
GetClassCenterBound<T>
|
||||
<<<NumBlocks(batch_size), kNumCUDAThreads, 0, dev_ctx.stream()>>>(
|
||||
batch_size,
|
||||
nranks,
|
||||
class_interval_ptr,
|
||||
cub_sort_keys_out_ptr,
|
||||
cub_sort_values_ptr,
|
||||
bound_index_ptr,
|
||||
bound_value_ptr);
|
||||
|
||||
// step 11: Calculate actual number of sampled class per device.
|
||||
// Since maybe num_positive_class_center > num_samples,
|
||||
// we need to ensure all positive class center per device are sampled.
|
||||
ActualNumSampledFunctor<T> actual_num_sampled_op(num_samples);
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(
|
||||
(cub::DeviceScan::InclusiveScan(cub_temp_storage_ptr,
|
||||
cub_temp_storage_bytes,
|
||||
bound_value_ptr,
|
||||
num_classes_per_device_ptr,
|
||||
actual_num_sampled_op,
|
||||
nranks + 1,
|
||||
dev_ctx.stream())));
|
||||
|
||||
// step 12: Calculate actual sampled class interval among nranks
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(
|
||||
(cub::DeviceScan::InclusiveSum(cub_temp_storage_ptr,
|
||||
cub_temp_storage_bytes,
|
||||
num_classes_per_device_ptr,
|
||||
class_interval_ptr,
|
||||
nranks + 1,
|
||||
dev_ctx.stream())));
|
||||
|
||||
// step 13: Get remapped label for output
|
||||
GetRemappedLabel<T>
|
||||
<<<NumBlocks(batch_size), kNumCUDAThreads, 0, dev_ctx.stream()>>>(
|
||||
batch_size,
|
||||
nranks,
|
||||
class_interval_ptr,
|
||||
bound_index_ptr,
|
||||
bound_value_ptr,
|
||||
cub_sort_keys_ptr,
|
||||
cub_sort_values_ptr,
|
||||
dev_ctx.template Alloc<T>(remapped_label));
|
||||
|
||||
// step 14: Get sampled class center for output
|
||||
Copy<Context>(dev_ctx,
|
||||
num_classes_per_device,
|
||||
CPUPlace(),
|
||||
true,
|
||||
&num_classes_per_device);
|
||||
T actual_num_samples = num_classes_per_device.data<T>()[rank + 1];
|
||||
sampled_local_class_center->Resize({actual_num_samples});
|
||||
|
||||
T* sampled_local_class_center_ptr =
|
||||
dev_ctx.template Alloc<T>(sampled_local_class_center);
|
||||
memory_utils::Copy(dev_ctx.GetPlace(),
|
||||
sampled_local_class_center_ptr,
|
||||
dev_ctx.GetPlace(),
|
||||
cub_sort_values_out_ptr,
|
||||
actual_num_samples * sizeof(T),
|
||||
nullptr);
|
||||
}
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(class_center_sample,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ClassCenterSampleKernel,
|
||||
int64_t,
|
||||
int) {}
|
||||
@@ -0,0 +1,83 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/clip_by_norm_kernel.h"
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/common/amp_type_traits.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/funcs/eigen/common.h"
|
||||
#include "paddle/phi/kernels/funcs/reduce_function.h"
|
||||
#include "paddle/phi/kernels/impl/clip_by_norm_kernel_impl.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void ClipByNormKernel(const Context& dev_ctx,
|
||||
const DenseTensor& in,
|
||||
float max_norm,
|
||||
DenseTensor* output) {
|
||||
if (typeid(T) == typeid(float)) {
|
||||
return ClipByNormFunctor<float, Context>(dev_ctx, in, max_norm, output);
|
||||
}
|
||||
auto input = ∈
|
||||
dev_ctx.template Alloc<T>(output);
|
||||
|
||||
PADDLE_ENFORCE_NOT_NULL(input,
|
||||
common::errors::InvalidArgument(
|
||||
"Input(X) of ClipByNormOp should not be null. "
|
||||
"Please check if it is created correctly."));
|
||||
std::vector<int> reduce_dims;
|
||||
reduce_dims.resize(input->dims().size());
|
||||
for (int i = 0; i < reduce_dims.size(); ++i) {
|
||||
reduce_dims[i] = i;
|
||||
}
|
||||
DenseTensor tmp_tensor;
|
||||
auto* tmp = &tmp_tensor;
|
||||
tmp->Resize({1});
|
||||
dev_ctx.template Alloc<float>(tmp);
|
||||
funcs::ReduceKernel<T, float, kps::AddFunctor, kps::SquareFunctor<T, float>>(
|
||||
dev_ctx, *input, tmp, kps::SquareFunctor<T, float>(), reduce_dims);
|
||||
auto tmp_eigen = EigenVector<float>::Flatten(*tmp);
|
||||
auto x_norm = tmp_eigen.sqrt();
|
||||
|
||||
auto x = EigenVector<T>::Flatten(*input);
|
||||
auto out = EigenVector<T>::Flatten(*output);
|
||||
auto* place = dev_ctx.eigen_device();
|
||||
|
||||
auto temp = (x_norm <= max_norm).template cast<float>();
|
||||
auto epsilon =
|
||||
((x_norm <= static_cast<float>(1e-30)).all().template cast<float>()) *
|
||||
static_cast<float>(1e-6);
|
||||
|
||||
auto scaling =
|
||||
(temp + (static_cast<float>(1) - temp) * max_norm / (x_norm + epsilon))
|
||||
.template cast<T>();
|
||||
Eigen::array<int, 1> one_dim{{1}};
|
||||
Eigen::DSizes<int, 1> m_dsize(input->numel());
|
||||
|
||||
out.device(*place) = x * scaling.reshape(one_dim).broadcast(m_dsize);
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(clip_by_norm,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ClipByNormKernel,
|
||||
float,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/clip_grad_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/clip_grad_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(clip_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ClipGradKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::bfloat16,
|
||||
phi::float16) {}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/clip_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/clip_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(clip,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ClipKernel,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t,
|
||||
phi::float16,
|
||||
phi::bfloat16) {}
|
||||
@@ -0,0 +1,288 @@
|
||||
// Copyright (c) 2024 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/gpu/collect_fpn_proposals_kernel.h"
|
||||
#include "paddle/phi/backends/gpu/cuda/cuda_graph_with_memory_pool.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_primitives.h"
|
||||
#include "paddle/phi/common/memory_utils.h"
|
||||
#include "paddle/phi/core/allocator.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/core/mixed_vector.h"
|
||||
#include "paddle/phi/kernels/funcs/concat_and_split_functor.h"
|
||||
#include "paddle/phi/kernels/funcs/cub.h"
|
||||
#include "paddle/phi/kernels/funcs/detection/bbox_util.h"
|
||||
#include "paddle/phi/kernels/funcs/for_range.h"
|
||||
#include "paddle/phi/kernels/funcs/gather.cu.h"
|
||||
#include "paddle/phi/kernels/funcs/strided_memcpy.h"
|
||||
#include "paddle/phi/kernels/impl/collect_fpn_proposals_kernel_impl.h"
|
||||
#include "paddle/utils/optional.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
static constexpr int kNumCUDAThreads = 64;
|
||||
static constexpr int kNumMaximumNumBlocks = 4096;
|
||||
|
||||
const int kBBoxSize = 4;
|
||||
|
||||
static inline int NumBlocks(const int N) {
|
||||
return std::min((N + kNumCUDAThreads - 1) / kNumCUDAThreads,
|
||||
kNumMaximumNumBlocks);
|
||||
}
|
||||
|
||||
static __global__ void GetLengthLoD(const int nthreads,
|
||||
const int* batch_ids,
|
||||
int* length_lod) {
|
||||
CUDA_KERNEL_LOOP(i, nthreads) { CudaAtomicAdd(length_lod + batch_ids[i], 1); }
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
void GPUCollectFpnProposalsOpKernel(
|
||||
const Context& dev_ctx,
|
||||
const std::vector<const DenseTensor*>& multi_level_rois,
|
||||
const std::vector<const DenseTensor*>& multi_level_scores,
|
||||
const optional<std::vector<const DenseTensor*>>& multi_level_rois_num,
|
||||
int post_nms_topn,
|
||||
DenseTensor* fpn_rois_out,
|
||||
DenseTensor* rois_num_out) {
|
||||
const auto roi_ins = multi_level_rois;
|
||||
const auto score_ins = multi_level_scores;
|
||||
auto fpn_rois = fpn_rois_out;
|
||||
|
||||
const int post_nms_topN = post_nms_topn;
|
||||
|
||||
// concat inputs along axis = 0
|
||||
int roi_offset = 0;
|
||||
int score_offset = 0;
|
||||
int total_roi_num = 0;
|
||||
for (size_t i = 0; i < roi_ins.size(); ++i) {
|
||||
total_roi_num += roi_ins[i]->dims()[0];
|
||||
}
|
||||
|
||||
int real_post_num = min(post_nms_topN, total_roi_num);
|
||||
fpn_rois->Resize({real_post_num, kBBoxSize});
|
||||
dev_ctx.template Alloc<T>(fpn_rois);
|
||||
DenseTensor concat_rois;
|
||||
DenseTensor concat_scores;
|
||||
concat_rois.Resize({total_roi_num, kBBoxSize});
|
||||
T* concat_rois_data = dev_ctx.template Alloc<T>(&concat_rois);
|
||||
concat_scores.Resize({total_roi_num, 1});
|
||||
T* concat_scores_data = dev_ctx.template Alloc<T>(&concat_scores);
|
||||
DenseTensor roi_batch_id_list;
|
||||
roi_batch_id_list.Resize({total_roi_num});
|
||||
int* roi_batch_id_data = dev_ctx.template HostAlloc<int>(&roi_batch_id_list);
|
||||
int index = 0;
|
||||
int lod_size;
|
||||
auto place = dev_ctx.GetPlace();
|
||||
|
||||
auto multi_rois_num = multi_level_rois_num
|
||||
? multi_level_rois_num.get()
|
||||
: std::vector<const DenseTensor*>();
|
||||
for (size_t i = 0; i < roi_ins.size(); ++i) {
|
||||
auto roi_in = roi_ins[i];
|
||||
auto score_in = score_ins[i];
|
||||
if (multi_rois_num.size() > 0) {
|
||||
DenseTensor temp;
|
||||
Copy(dev_ctx, *multi_rois_num[i], CPUPlace(), true, &temp);
|
||||
const int* length_in = temp.data<int>();
|
||||
lod_size = multi_rois_num[i]->numel();
|
||||
for (size_t n = 0; n < lod_size; ++n) {
|
||||
for (size_t j = 0; j < length_in[n]; ++j) {
|
||||
roi_batch_id_data[index++] = n;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto length_in = roi_in->lod().back();
|
||||
lod_size = length_in.size() - 1;
|
||||
for (size_t n = 0; n < lod_size; ++n) {
|
||||
for (size_t j = length_in[n]; j < length_in[n + 1]; ++j) {
|
||||
roi_batch_id_data[index++] = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memory_utils::Copy(place,
|
||||
concat_rois_data + roi_offset,
|
||||
place,
|
||||
roi_in->data<T>(),
|
||||
roi_in->numel() * sizeof(T),
|
||||
dev_ctx.stream());
|
||||
memory_utils::Copy(place,
|
||||
concat_scores_data + score_offset,
|
||||
place,
|
||||
score_in->data<T>(),
|
||||
score_in->numel() * sizeof(T),
|
||||
dev_ctx.stream());
|
||||
roi_offset += roi_in->numel();
|
||||
score_offset += score_in->numel();
|
||||
}
|
||||
|
||||
// copy batch id list to GPU
|
||||
DenseTensor roi_batch_id_list_gpu;
|
||||
Copy(dev_ctx,
|
||||
roi_batch_id_list,
|
||||
dev_ctx.GetPlace(),
|
||||
false,
|
||||
&roi_batch_id_list_gpu);
|
||||
|
||||
DenseTensor index_in_t;
|
||||
index_in_t.Resize({total_roi_num});
|
||||
int* idx_in = dev_ctx.template Alloc<int>(&index_in_t);
|
||||
funcs::ForRange<GPUContext> for_range_total(dev_ctx, total_roi_num);
|
||||
for_range_total(funcs::RangeInitFunctor{0, 1, idx_in});
|
||||
|
||||
DenseTensor keys_out_t;
|
||||
keys_out_t.Resize({total_roi_num});
|
||||
T* keys_out = dev_ctx.template Alloc<T>(&keys_out_t);
|
||||
DenseTensor index_out_t;
|
||||
index_out_t.Resize({total_roi_num});
|
||||
int* idx_out = dev_ctx.template Alloc<int>(&index_out_t);
|
||||
|
||||
// Determine temporary device storage requirements
|
||||
size_t temp_storage_bytes = 0;
|
||||
cub::DeviceRadixSort::SortPairsDescending<T, int>(nullptr,
|
||||
temp_storage_bytes,
|
||||
concat_scores.data<T>(),
|
||||
keys_out,
|
||||
idx_in,
|
||||
idx_out,
|
||||
total_roi_num,
|
||||
0,
|
||||
sizeof(T) * 8,
|
||||
dev_ctx.stream());
|
||||
// Allocate temporary storage
|
||||
auto d_temp_storage = memory_utils::Alloc(place, temp_storage_bytes);
|
||||
|
||||
// Run sorting operation
|
||||
// sort score to get corresponding index
|
||||
cub::DeviceRadixSort::SortPairsDescending<T, int>(d_temp_storage->ptr(),
|
||||
temp_storage_bytes,
|
||||
concat_scores.data<T>(),
|
||||
keys_out,
|
||||
idx_in,
|
||||
idx_out,
|
||||
total_roi_num,
|
||||
0,
|
||||
sizeof(T) * 8,
|
||||
dev_ctx.stream());
|
||||
index_out_t.Resize({real_post_num});
|
||||
DenseTensor sorted_rois;
|
||||
sorted_rois.Resize({real_post_num, kBBoxSize});
|
||||
dev_ctx.template Alloc<T>(&sorted_rois);
|
||||
DenseTensor sorted_batch_id;
|
||||
sorted_batch_id.Resize({real_post_num});
|
||||
dev_ctx.template Alloc<int>(&sorted_batch_id);
|
||||
funcs::GPUGather<T>(dev_ctx, concat_rois, index_out_t, &sorted_rois);
|
||||
funcs::GPUGather<int>(
|
||||
dev_ctx, roi_batch_id_list_gpu, index_out_t, &sorted_batch_id);
|
||||
|
||||
DenseTensor batch_index_t;
|
||||
batch_index_t.Resize({real_post_num});
|
||||
int* batch_idx_in = dev_ctx.template Alloc<int>(&batch_index_t);
|
||||
funcs::ForRange<GPUContext> for_range_post(dev_ctx, real_post_num);
|
||||
for_range_post(funcs::RangeInitFunctor{0, 1, batch_idx_in});
|
||||
|
||||
DenseTensor out_id_t;
|
||||
out_id_t.Resize({real_post_num});
|
||||
int* out_id_data = dev_ctx.template Alloc<int>(&out_id_t);
|
||||
// Determine temporary device storage requirements
|
||||
temp_storage_bytes = 0;
|
||||
cub::DeviceRadixSort::SortPairs<int, int>(nullptr,
|
||||
temp_storage_bytes,
|
||||
sorted_batch_id.data<int>(),
|
||||
out_id_data,
|
||||
batch_idx_in,
|
||||
index_out_t.data<int>(),
|
||||
real_post_num,
|
||||
0,
|
||||
sizeof(int) * 8,
|
||||
dev_ctx.stream());
|
||||
// Allocate temporary storage
|
||||
d_temp_storage = memory_utils::Alloc(place, temp_storage_bytes);
|
||||
|
||||
// Run sorting operation
|
||||
// sort batch_id to get corresponding index
|
||||
cub::DeviceRadixSort::SortPairs<int, int>(d_temp_storage->ptr(),
|
||||
temp_storage_bytes,
|
||||
sorted_batch_id.data<int>(),
|
||||
out_id_data,
|
||||
batch_idx_in,
|
||||
index_out_t.data<int>(),
|
||||
real_post_num,
|
||||
0,
|
||||
sizeof(int) * 8,
|
||||
dev_ctx.stream());
|
||||
|
||||
funcs::GPUGather<T>(dev_ctx, sorted_rois, index_out_t, fpn_rois);
|
||||
|
||||
DenseTensor length_lod;
|
||||
length_lod.Resize({lod_size});
|
||||
int* length_lod_data = dev_ctx.template Alloc<int>(&length_lod);
|
||||
funcs::SetConstant<GPUContext, int> set_zero;
|
||||
set_zero(dev_ctx, &length_lod, static_cast<int>(0));
|
||||
|
||||
int blocks = NumBlocks(real_post_num);
|
||||
int threads = kNumCUDAThreads;
|
||||
|
||||
// get length-based lod by batch ids
|
||||
GetLengthLoD<<<blocks, threads, 0, dev_ctx.stream()>>>(
|
||||
real_post_num, out_id_data, length_lod_data);
|
||||
PADDLE_ENFORCE_EQ(
|
||||
backends::gpu::IsCUDAGraphCapturing(),
|
||||
false,
|
||||
common::errors::InvalidArgument(
|
||||
"CollectFpnProposals does not support CUDA Graph capture: async D2H "
|
||||
"copy to local vector 'length_lod_cpu' will bake the destination "
|
||||
"address into the graph; on replay the vector is re-created at a "
|
||||
"different address, causing a dangling-pointer write."));
|
||||
std::vector<int> length_lod_cpu(lod_size);
|
||||
memory_utils::Copy(CPUPlace(),
|
||||
length_lod_cpu.data(),
|
||||
place,
|
||||
length_lod_data,
|
||||
sizeof(int) * lod_size,
|
||||
dev_ctx.stream());
|
||||
dev_ctx.Wait();
|
||||
|
||||
std::vector<size_t> offset(1, 0);
|
||||
for (int i = 0; i < lod_size; ++i) {
|
||||
offset.emplace_back(offset.back() + length_lod_cpu[i]);
|
||||
}
|
||||
|
||||
if (rois_num_out != nullptr) {
|
||||
auto* rois_num = rois_num_out;
|
||||
rois_num->Resize({lod_size});
|
||||
int* rois_num_data = dev_ctx.template Alloc<int>(rois_num);
|
||||
memory_utils::Copy(place,
|
||||
rois_num_data,
|
||||
place,
|
||||
length_lod_data,
|
||||
lod_size * sizeof(int),
|
||||
dev_ctx.stream());
|
||||
}
|
||||
|
||||
LegacyLoD lod;
|
||||
lod.emplace_back(offset);
|
||||
fpn_rois->set_lod(lod);
|
||||
}
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(collect_fpn_proposals,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::GPUCollectFpnProposalsOpKernel,
|
||||
float,
|
||||
double) {
|
||||
kernel->InputAt(2).SetDataType(phi::DataType::INT32);
|
||||
kernel->OutputAt(1).SetDataType(phi::DataType::INT32);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
|
||||
namespace phi {
|
||||
template <typename T, typename Context>
|
||||
void GPUCollectFpnProposalsOpKernel(
|
||||
const Context& dev_ctx,
|
||||
const std::vector<const DenseTensor*>& multi_level_rois,
|
||||
const std::vector<const DenseTensor*>& multi_level_scores,
|
||||
const optional<std::vector<const DenseTensor*>>& multi_level_rois_num,
|
||||
int post_nms_topn,
|
||||
DenseTensor* fpn_rois_out,
|
||||
DenseTensor* rois_num_out);
|
||||
} // namespace phi
|
||||
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2024 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/comm_init_all_kernel.h"
|
||||
#include <string>
|
||||
#include "glog/logging.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
#include "paddle/phi/core/platform/collective_helper.h"
|
||||
#endif
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void CommInitAllKernel(const Context& dev_ctx,
|
||||
const std::vector<int>& devices_input,
|
||||
int ring_id) {
|
||||
#if defined(PADDLE_WITH_NCCL) || defined(PADDLE_WITH_RCCL)
|
||||
std::vector<int> devices = devices_input;
|
||||
if (devices.empty()) {
|
||||
devices = backends::gpu::GetSelectedDevices();
|
||||
}
|
||||
|
||||
paddle::platform::NCCLCommContext::Instance().CreateAllNCCLComms(devices,
|
||||
ring_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(
|
||||
comm_init_all, GPU, ALL_LAYOUT, phi::CommInitAllKernel, float) {}
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "paddle/phi/kernels/complex_grad_kernel.h"
|
||||
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/complex_grad_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(imag_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ImagGradKernel,
|
||||
phi::complex64,
|
||||
phi::complex128) {
|
||||
kernel->InputAt(0).SetDataType(phi::dtype::ToReal(kernel_key.dtype()));
|
||||
}
|
||||
|
||||
PD_REGISTER_KERNEL(real_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::RealGradKernel,
|
||||
phi::complex64,
|
||||
phi::complex128) {
|
||||
kernel->InputAt(0).SetDataType(phi::dtype::ToReal(kernel_key.dtype()));
|
||||
}
|
||||
|
||||
PD_REGISTER_KERNEL(
|
||||
complex_grad, GPU, ALL_LAYOUT, phi::ComplexGradKernel, float, double) {
|
||||
kernel->InputAt(2).SetDataType(phi::dtype::ToComplex(kernel_key.dtype()));
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2021 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/complex_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/kernels/impl/complex_kernel_impl.h"
|
||||
|
||||
PD_REGISTER_KERNEL(conj,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::ConjKernel,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
phi::complex64,
|
||||
phi::complex128,
|
||||
float,
|
||||
double,
|
||||
int,
|
||||
int64_t) {}
|
||||
|
||||
PD_REGISTER_KERNEL(
|
||||
real, GPU, ALL_LAYOUT, phi::RealKernel, phi::complex64, phi::complex128) {
|
||||
kernel->OutputAt(0).SetDataType(phi::dtype::ToReal(kernel_key.dtype()));
|
||||
}
|
||||
|
||||
PD_REGISTER_KERNEL(
|
||||
imag, GPU, ALL_LAYOUT, phi::ImagKernel, phi::complex64, phi::complex128) {
|
||||
kernel->OutputAt(0).SetDataType(phi::dtype::ToReal(kernel_key.dtype()));
|
||||
}
|
||||
|
||||
PD_REGISTER_KERNEL(
|
||||
complex, GPU, ALL_LAYOUT, phi::ComplexKernel, float, double) {
|
||||
kernel->OutputAt(0).SetDataType(phi::dtype::ToComplex(kernel_key.dtype()));
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user