chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
// 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/prelu_grad_kernel.h"
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#include "paddle/phi/core/kernel_registry.h"
|
||||
#include "paddle/phi/core/tensor_meta.h"
|
||||
#include "paddle/phi/kernels/empty_kernel.h"
|
||||
#include "paddle/phi/kernels/full_kernel.h"
|
||||
#include "paddle/phi/kernels/funcs/reduce_function.h"
|
||||
#include "paddle/phi/kernels/gpu/prelu_funcs.h"
|
||||
#include "paddle/phi/kernels/primitive/functor_primitives.h"
|
||||
namespace phi {
|
||||
|
||||
enum PRELU_MODE { Element, ChannelFirst, ChannelLast, PRELU_Scalar };
|
||||
|
||||
template <typename T>
|
||||
__global__ void PReluOpGradKernel(const T* x_ptr,
|
||||
const T* alpha_ptr,
|
||||
const T* out_grad_ptr,
|
||||
T* x_grad_ptr,
|
||||
T* alpha_grad_ptr,
|
||||
size_t channel_num,
|
||||
size_t plane_size,
|
||||
size_t spatial_size,
|
||||
size_t numel,
|
||||
PRELU_MODE mode) {
|
||||
CUDA_KERNEL_LOOP_TYPE(index, numel, int64_t) {
|
||||
T scale;
|
||||
if (mode == Element) {
|
||||
size_t element_index = index % spatial_size;
|
||||
scale = alpha_ptr[element_index];
|
||||
} else if (mode == ChannelFirst) {
|
||||
size_t temp = index / plane_size;
|
||||
size_t channel_index = temp % channel_num;
|
||||
scale = alpha_ptr[channel_index];
|
||||
} else if (mode == ChannelLast) {
|
||||
size_t channel_index = index % channel_num;
|
||||
scale = alpha_ptr[channel_index];
|
||||
} else {
|
||||
scale = alpha_ptr[0];
|
||||
}
|
||||
T x = x_ptr[index];
|
||||
T out_grad = out_grad_ptr[index];
|
||||
T zero = static_cast<T>(0);
|
||||
if (x_grad_ptr != nullptr)
|
||||
x_grad_ptr[index] = (x > zero) ? out_grad : scale * out_grad;
|
||||
if (alpha_grad_ptr != nullptr)
|
||||
alpha_grad_ptr[index] = (x > zero) ? zero : x * out_grad;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class PreluOpGradFunctor {
|
||||
public:
|
||||
void operator()(gpuStream_t stream,
|
||||
const T* x,
|
||||
const T* alpha,
|
||||
const T* out_grad,
|
||||
T* x_grad,
|
||||
T* alpha_grad,
|
||||
const DDim& input_dims,
|
||||
PRELU_MODE mode) {
|
||||
size_t numel = 1;
|
||||
for (size_t i = 0; i < input_dims.size(); ++i) {
|
||||
numel *= input_dims[i];
|
||||
}
|
||||
|
||||
size_t plane_size;
|
||||
size_t spatial_size;
|
||||
size_t channel;
|
||||
if (mode == PRELU_Scalar) {
|
||||
plane_size = 1;
|
||||
spatial_size = 1;
|
||||
channel = 1;
|
||||
} else {
|
||||
plane_size = numel / input_dims[0] / input_dims[1];
|
||||
spatial_size = numel / input_dims[0];
|
||||
channel = mode == ChannelLast ? input_dims[input_dims.size() - 1]
|
||||
: input_dims[1];
|
||||
}
|
||||
|
||||
PReluOpGradKernel<T>
|
||||
<<<PADDLE_GET_BLOCKS(numel), CUDA_NUM_THREADS, 0, stream>>>(
|
||||
x,
|
||||
alpha,
|
||||
out_grad,
|
||||
x_grad,
|
||||
alpha_grad,
|
||||
channel,
|
||||
plane_size,
|
||||
spatial_size,
|
||||
numel,
|
||||
mode);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Context>
|
||||
void PReluGradKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const DenseTensor& alpha,
|
||||
const DenseTensor& out_grad,
|
||||
const std::string& data_format,
|
||||
const std::string& mode,
|
||||
DenseTensor* x_grad,
|
||||
DenseTensor* alpha_grad) {
|
||||
dev_ctx.template Alloc<T>(x_grad);
|
||||
if (x_grad->numel() == 0) {
|
||||
if (alpha_grad) {
|
||||
Full<T, Context>(dev_ctx, alpha_grad->dims(), 0, alpha_grad);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const T* x_ptr = x.data<T>();
|
||||
const T* alpha_ptr = alpha.data<T>();
|
||||
const T* out_grad_ptr = out_grad.data<T>();
|
||||
T* x_grad_ptr = x_grad ? dev_ctx.template Alloc<T>(x_grad) : nullptr;
|
||||
T* alpha_grad_ptr =
|
||||
alpha_grad ? dev_ctx.template Alloc<T>(alpha_grad) : nullptr;
|
||||
|
||||
if (!x_grad && !alpha_grad) return;
|
||||
|
||||
int64_t numel = x.numel();
|
||||
auto dim = x.dims();
|
||||
auto x_rank = dim.size();
|
||||
auto stream = dev_ctx.stream();
|
||||
|
||||
T* alpha_grad_tmp_ptr;
|
||||
DenseTensor alpha_grad_tmp;
|
||||
if (alpha_grad_ptr == nullptr) {
|
||||
alpha_grad_tmp_ptr = alpha_grad_ptr;
|
||||
} else {
|
||||
DenseTensorMeta alpha_grad_meta(
|
||||
alpha_grad->dtype(), dim, alpha_grad->layout());
|
||||
alpha_grad_tmp = Empty(dev_ctx, std::move(alpha_grad_meta));
|
||||
alpha_grad_tmp_ptr = alpha_grad_tmp.data<T>();
|
||||
}
|
||||
|
||||
PRELU_MODE m;
|
||||
bool channel_last = false;
|
||||
if (mode == "element") {
|
||||
m = Element;
|
||||
} else if (mode == "channel") {
|
||||
channel_last = data_format == "NHWC";
|
||||
m = channel_last ? ChannelLast : ChannelFirst;
|
||||
} else {
|
||||
m = PRELU_Scalar;
|
||||
}
|
||||
PreluOpGradFunctor<T> prelu_grad;
|
||||
prelu_grad(stream,
|
||||
x_ptr,
|
||||
alpha_ptr,
|
||||
out_grad_ptr,
|
||||
x_grad_ptr,
|
||||
alpha_grad_tmp_ptr,
|
||||
dim,
|
||||
m);
|
||||
|
||||
if (alpha_grad_tmp_ptr == nullptr) return;
|
||||
|
||||
std::vector<int> reduce_dims;
|
||||
for (size_t i = 0; i < dim.size(); i++) {
|
||||
if (mode == "channel" && !channel_last && i == 1) continue;
|
||||
if (mode == "channel" && channel_last && i == dim.size() - 1) continue;
|
||||
if (mode == "element" && i != 0) continue;
|
||||
reduce_dims.push_back(i);
|
||||
}
|
||||
|
||||
funcs::ReduceKernel<T, T, kps::AddFunctor, kps::IdentityFunctor<T>>(
|
||||
static_cast<const GPUContext&>(dev_ctx),
|
||||
alpha_grad_tmp,
|
||||
alpha_grad,
|
||||
kps::IdentityFunctor<T>(),
|
||||
reduce_dims);
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
|
||||
PD_REGISTER_KERNEL(prelu_grad,
|
||||
GPU,
|
||||
ALL_LAYOUT,
|
||||
phi::PReluGradKernel,
|
||||
float,
|
||||
phi::float16,
|
||||
phi::bfloat16,
|
||||
double) {}
|
||||
Reference in New Issue
Block a user