Files
2026-07-13 12:40:42 +08:00

704 lines
27 KiB
Plaintext

// 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/instance_norm_grad_kernel.h"
#include "glog/logging.h"
#include "paddle/common/enforce.h"
#include "paddle/common/layout.h"
#include "paddle/phi/backends/gpu/gpu_context.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/funcs/norm_utils.h"
#include "paddle/phi/kernels/gpu/instance_norm_utils.h"
namespace phi {
template <typename T, int BlockDim>
static __global__ void GradComputeDX(const T *dy,
const BatchNormParamType<T> *scale,
const BatchNormParamType<T> *mean,
const T *x,
const BatchNormParamType<T> *variance,
const int C,
const int64_t sample_size,
T *dx) {
int64_t beg_idx = static_cast<int64_t>(blockIdx.x) * sample_size +
static_cast<int64_t>(threadIdx.x);
int64_t end_idx = (static_cast<int64_t>(blockIdx.x) + 1) * sample_size;
int ncid = blockIdx.x;
int c = ncid % C;
BatchNormParamType<T> mean_val = mean[ncid];
BatchNormParamType<T> inv_var_val = variance[ncid];
typedef cub::BlockReduce<BatchNormParamType<T>, BlockDim> BlockReduce;
__shared__ typename BlockReduce::TempStorage dy_storage;
__shared__ typename BlockReduce::TempStorage dy_x_sub_mean_storage;
__shared__ BatchNormParamType<T> dy_sum_val;
__shared__ BatchNormParamType<T> dy_x_sub_mean_sum_val;
BatchNormParamType<T> dy_sum = static_cast<BatchNormParamType<T>>(0);
BatchNormParamType<T> dy_x_sub_mean_sum =
static_cast<BatchNormParamType<T>>(0);
for (int64_t i = beg_idx; i < end_idx; i += BlockDim) {
BatchNormParamType<T> dy_i = static_cast<BatchNormParamType<T>>(dy[i]);
dy_sum += dy_i;
dy_x_sub_mean_sum +=
dy_i * (static_cast<BatchNormParamType<T>>(x[i]) - mean_val);
}
dy_sum = BlockReduce(dy_storage).Reduce(dy_sum, cub::Sum());
dy_x_sub_mean_sum =
BlockReduce(dy_x_sub_mean_storage).Reduce(dy_x_sub_mean_sum, cub::Sum());
if (threadIdx.x == 0) {
dy_sum_val = dy_sum;
dy_x_sub_mean_sum_val = dy_x_sub_mean_sum;
}
__syncthreads();
for (int64_t i = beg_idx; i < end_idx; i += BlockDim) {
dx[i] = static_cast<T>(
(static_cast<BatchNormParamType<T>>(dy[i]) -
dy_sum_val / static_cast<BatchNormParamType<T>>(sample_size) -
(static_cast<BatchNormParamType<T>>(x[i]) - mean_val) *
dy_x_sub_mean_sum_val * inv_var_val * inv_var_val / sample_size) *
scale[c] * inv_var_val);
}
}
static __device__ __forceinline__ float real_sqrt(float x) {
return 1. / sqrtf(x);
}
static __device__ __forceinline__ double real_sqrt(double x) {
return 1. / sqrt(x);
}
template <typename T, typename AccT, int BlockDim>
__global__ void DoubleGradComputeDX(const T *x,
const AccT *mean,
const AccT *variance,
const T *ddx,
const T *dy,
const AccT *scale,
const AccT *ddscale,
int C,
int64_t sample_size,
const double epsilon,
T *dx) {
int64_t beg_idx = static_cast<int64_t>(blockIdx.x) * sample_size +
static_cast<int64_t>(threadIdx.x);
int64_t end_idx = (static_cast<int64_t>(blockIdx.x) + 1) * sample_size;
int ncid = blockIdx.x;
int c = ncid % C;
AccT mean_val = mean[ncid];
AccT var_val = variance[ncid];
typedef cub::BlockReduce<AccT, BlockDim> BlockReduce;
__shared__ typename BlockReduce::TempStorage dy_storage;
__shared__ typename BlockReduce::TempStorage ddx_storage;
__shared__ typename BlockReduce::TempStorage dy_mul_ddx_storage;
__shared__ typename BlockReduce::TempStorage dy_mul_x_sub_mean_storage;
__shared__ typename BlockReduce::TempStorage ddx_mul_x_sub_mean_storage;
__shared__ AccT dy_sum_val;
__shared__ AccT ddx_sum_val;
__shared__ AccT dy_mul_ddx_sum_val;
__shared__ AccT dy_mul_x_sub_mean_sum_val;
__shared__ AccT ddx_mul_x_sub_mean_sum_val;
AccT dy_sum = 0;
AccT ddx_sum = 0;
AccT dy_mul_ddx_sum = 0;
AccT dy_mul_x_sub_mean_sum = 0;
AccT ddx_mul_x_sub_mean_sum = 0;
for (int64_t i = beg_idx; i < end_idx; i += BlockDim) {
AccT ddx_i = static_cast<AccT>(ddx[i]);
AccT dy_i = static_cast<AccT>(dy[i]);
AccT tmp = static_cast<AccT>(x[i]) - mean_val;
dy_sum += dy_i;
ddx_sum += ddx_i;
dy_mul_ddx_sum += (ddx_i * dy_i);
dy_mul_x_sub_mean_sum += (dy_i * tmp);
ddx_mul_x_sub_mean_sum += (ddx_i * tmp);
}
dy_sum = BlockReduce(dy_storage).Reduce(dy_sum, cub::Sum());
ddx_sum = BlockReduce(ddx_storage).Reduce(ddx_sum, cub::Sum());
dy_mul_ddx_sum =
BlockReduce(dy_mul_ddx_storage).Reduce(dy_mul_ddx_sum, cub::Sum());
dy_mul_x_sub_mean_sum = BlockReduce(dy_mul_x_sub_mean_storage)
.Reduce(dy_mul_x_sub_mean_sum, cub::Sum());
ddx_mul_x_sub_mean_sum = BlockReduce(ddx_mul_x_sub_mean_storage)
.Reduce(ddx_mul_x_sub_mean_sum, cub::Sum());
if (threadIdx.x == 0) {
dy_sum_val = dy_sum;
ddx_sum_val = ddx_sum;
dy_mul_ddx_sum_val = dy_mul_ddx_sum;
dy_mul_x_sub_mean_sum_val = dy_mul_x_sub_mean_sum;
ddx_mul_x_sub_mean_sum_val = ddx_mul_x_sub_mean_sum;
}
__syncthreads();
if (ddx != nullptr) {
for (int64_t i = beg_idx; i < end_idx; i += BlockDim) {
AccT tmp = static_cast<AccT>(dx[i]);
tmp +=
((static_cast<AccT>(x[i]) - mean_val) * var_val * var_val * var_val /
sample_size *
(ddx_sum_val * dy_sum_val / sample_size - dy_mul_ddx_sum_val +
3. * dy_mul_x_sub_mean_sum_val * var_val *
ddx_mul_x_sub_mean_sum_val * var_val / sample_size) +
ddx_mul_x_sub_mean_sum_val * var_val / sample_size * var_val *
var_val * (dy_sum_val / sample_size - static_cast<AccT>(dy[i])) +
dy_mul_x_sub_mean_sum_val * var_val / sample_size * var_val *
var_val *
(ddx_sum_val / sample_size - static_cast<AccT>(ddx[i]))) *
scale[c];
dx[i] = static_cast<T>(tmp);
}
}
__syncthreads();
if (ddscale != nullptr) {
for (int64_t i = beg_idx; i < end_idx; i += BlockDim) {
AccT tmp = static_cast<AccT>(dx[i]);
tmp += (static_cast<AccT>(dy[i]) * var_val -
dy_sum_val / sample_size * var_val -
(static_cast<AccT>(x[i]) - mean_val) * var_val *
dy_mul_x_sub_mean_sum_val * var_val / sample_size) *
ddscale[c];
dx[i] = static_cast<T>(tmp);
}
}
}
template <typename T, typename AccT, int BlockDim>
__global__ void DoubleGradComputeDDY(const T *x,
const AccT *mean,
const AccT *variance,
const AccT *ddscale,
const AccT *ddbias,
const T *ddx,
const AccT *scale,
int C,
int64_t sample_size,
const double epsilon,
T *ddy) {
int64_t beg_idx = static_cast<int64_t>(blockIdx.x) * sample_size +
static_cast<int64_t>(threadIdx.x);
int64_t end_idx = (static_cast<int64_t>(blockIdx.x) + 1) * sample_size;
int ncid = blockIdx.x;
int c = ncid % C;
AccT mean_val = mean[ncid];
AccT var_val = variance[ncid];
typedef cub::BlockReduce<AccT, BlockDim> BlockReduce;
__shared__ typename BlockReduce::TempStorage ddx_storage;
__shared__ typename BlockReduce::TempStorage ddx_mul_x_sub_mean_storage;
__shared__ AccT ddx_sum_val;
__shared__ AccT ddx_mul_x_sub_mean_sum_val;
AccT ddx_sum = 0;
AccT ddx_mul_x_sub_mean_sum = 0;
for (int64_t i = beg_idx; i < end_idx; i += BlockDim) {
AccT ddx_i = static_cast<AccT>(ddx[i]);
ddx_sum += ddx_i;
ddx_mul_x_sub_mean_sum += (ddx_i * (static_cast<AccT>(x[i]) - mean_val));
}
ddx_sum = BlockReduce(ddx_storage).Reduce(ddx_sum, cub::Sum());
ddx_mul_x_sub_mean_sum = BlockReduce(ddx_mul_x_sub_mean_storage)
.Reduce(ddx_mul_x_sub_mean_sum, cub::Sum());
if (threadIdx.x == 0) {
ddx_sum_val = ddx_sum;
ddx_mul_x_sub_mean_sum_val = ddx_mul_x_sub_mean_sum;
}
__syncthreads();
if (ddx != nullptr) {
for (int64_t i = beg_idx; i < end_idx; i += BlockDim) {
AccT tmp = static_cast<AccT>(ddy[i]);
tmp += scale[c] * var_val *
(static_cast<AccT>(ddx[i]) - ddx_sum_val / sample_size -
(static_cast<AccT>(x[i]) - mean_val) * var_val *
ddx_mul_x_sub_mean_sum_val * var_val / sample_size);
ddy[i] = static_cast<T>(tmp);
}
}
__syncthreads();
if (ddscale != nullptr) {
for (int64_t i = beg_idx; i < end_idx; i += BlockDim) {
AccT tmp = static_cast<AccT>(ddy[i]);
tmp += (static_cast<AccT>(x[i]) - mean_val) * var_val * ddscale[c];
ddy[i] = static_cast<T>(tmp);
}
}
__syncthreads();
if (ddbias != nullptr) {
for (int64_t i = beg_idx; i < end_idx; i += BlockDim) {
ddy[i] = static_cast<T>(static_cast<AccT>(ddy[i]) + ddbias[c]);
}
}
}
template <typename T, typename AccT, int BlockDim>
__global__ void DoubleGradComputeDScale(const T *x,
const AccT *mean,
const AccT *variance,
const T *ddx,
const T *dy,
int C,
int64_t sample_size,
const double epsilon,
AccT *dscale) {
int64_t beg_idx = static_cast<int64_t>(blockIdx.x) * sample_size +
static_cast<int64_t>(threadIdx.x);
int64_t end_idx = (static_cast<int64_t>(blockIdx.x) + 1) * sample_size;
int ncid = blockIdx.x;
int c = ncid % C;
AccT mean_val = mean[ncid];
AccT var_val = variance[ncid];
typedef cub::BlockReduce<AccT, BlockDim> BlockReduce;
__shared__ typename BlockReduce::TempStorage dy_storage;
__shared__ typename BlockReduce::TempStorage dy_mul_x_sub_mean_storage;
__shared__ typename BlockReduce::TempStorage dscale_tmp_storage;
__shared__ AccT dy_sum_val;
__shared__ AccT dy_mul_x_sub_mean_sum_val;
AccT dy_sum = 0;
AccT dy_mul_x_sub_mean_sum = 0;
for (int64_t i = beg_idx; i < end_idx; i += BlockDim) {
AccT dy_i = static_cast<AccT>(dy[i]);
dy_sum += dy_i;
dy_mul_x_sub_mean_sum += (dy_i * (static_cast<AccT>(x[i]) - mean_val));
}
dy_sum = BlockReduce(dy_storage).Reduce(dy_sum, cub::Sum());
dy_mul_x_sub_mean_sum = BlockReduce(dy_mul_x_sub_mean_storage)
.Reduce(dy_mul_x_sub_mean_sum, cub::Sum());
if (threadIdx.x == 0) {
dy_sum_val = dy_sum;
dy_mul_x_sub_mean_sum_val = dy_mul_x_sub_mean_sum;
}
__syncthreads();
if (ddx != nullptr) {
AccT dscale_tmp = 0;
for (int64_t i = beg_idx; i < end_idx; i += BlockDim) {
dscale_tmp +=
static_cast<AccT>(ddx[i]) * var_val *
(static_cast<AccT>(dy[i]) - dy_sum_val / sample_size -
dy_mul_x_sub_mean_sum_val * (static_cast<AccT>(x[i]) - mean_val) *
var_val * var_val / sample_size);
}
dscale_tmp = BlockReduce(dscale_tmp_storage).Reduce(dscale_tmp, cub::Sum());
if (threadIdx.x == 0) {
dscale[ncid] += dscale_tmp;
}
__syncthreads();
}
}
template <typename T, typename Context>
void InstanceNormGradKernel(const Context &dev_ctx,
const DenseTensor &x,
const optional<DenseTensor> &scale,
const optional<DenseTensor> &bias UNUSED,
const DenseTensor &saved_mean,
const DenseTensor &saved_variance,
const DenseTensor &d_y,
float epsilon_f,
DenseTensor *d_x,
DenseTensor *d_scale,
DenseTensor *d_bias) {
using AccT = typename MPTypeTrait<T>::Type;
double epsilon = static_cast<double>(epsilon_f);
const auto *scale_ptr = scale.get_ptr();
const auto &x_dims = x.dims();
int N, C, H, W, D;
funcs::ExtractNCWHD(x_dims, DataLayout::NCHW, &N, &C, &H, &W, &D);
const int64_t NxC_64 = static_cast<int64_t>(N) * C;
PADDLE_ENFORCE_LE_INT_MAX(NxC_64, "NxC");
const int NxC = static_cast<int>(NxC_64);
DenseTensor x_tmp, d_y_tmp;
x_tmp.ShareDataWith(x).Resize({1, NxC, H, W, D});
d_y_tmp.ShareDataWith(d_y).Resize({1, NxC, H, W, D});
funcs::SetConstant<GPUContext, AccT> set_constant;
dev_ctx.template Alloc<T>(d_x);
if (x.numel() == 0) {
if (d_scale) {
dev_ctx.template Alloc<AccT>(d_scale);
set_constant(dev_ctx, d_scale, static_cast<AccT>(0));
}
if (d_bias) {
dev_ctx.template Alloc<AccT>(d_bias);
set_constant(dev_ctx, d_bias, static_cast<AccT>(0));
}
return;
}
if (d_scale && d_bias) {
dev_ctx.template Alloc<AccT>(d_scale);
dev_ctx.template Alloc<AccT>(d_bias);
}
if (scale_ptr) {
PADDLE_ENFORCE_EQ(
scale_ptr->dims().size(),
1UL,
common::errors::InvalidArgument(
"The `shape` in InstanceNormOp is invalid: "
"the size of scale's dimensions must be equal to 1. But "
"received: the size of scale's dimensions "
"is [%d]",
scale_ptr->dims().size()));
PADDLE_ENFORCE_EQ(scale_ptr->dims()[0],
C,
common::errors::InvalidArgument(
"The `shape` in InstanceNormOp is invalid: "
"the first dimension of scale must be equal to "
"Channels([%d]). But received: "
"the first dimension of scale is [%d],"
"the dimensions of scale is [%s], ",
C,
scale_ptr->dims()[0],
scale_ptr->dims()));
}
const int64_t n = x.numel();
const int block = 512;
int max_threads = dev_ctx.GetMaxPhysicalThreadCount();
const int max_blocks = std::max(max_threads / block, 1);
const int grid = std::min(NxC, max_blocks);
const int grid1 = (C + block - 1) / block;
DenseTensor scale_tmp;
scale_tmp.Resize({NxC});
dev_ctx.template Alloc<AccT>(&scale_tmp);
DenseTensor d_scale_tmp;
d_scale_tmp.Resize({NxC});
dev_ctx.template Alloc<AccT>(&d_scale_tmp);
DenseTensor d_bias_tmp;
d_bias_tmp.Resize({NxC});
dev_ctx.template Alloc<AccT>(&d_bias_tmp);
if (scale_ptr) {
repeat_param<AccT><<<grid, block, 0, dev_ctx.stream()>>>(
scale_ptr->data<AccT>(), scale_tmp.data<AccT>(), N, C);
} else {
set_constant(dev_ctx, &scale_tmp, static_cast<AccT>(1));
}
std::vector<int> dims;
std::vector<int> strides;
const int64_t sample_size_64 = static_cast<int64_t>(H) * W * D;
const int64_t stride0 = NxC_64 * sample_size_64;
const int64_t stride1 = sample_size_64;
const int64_t stride2 = static_cast<int64_t>(W) * D;
PADDLE_ENFORCE_LE_INT_MAX(stride0, "cudnn tensor descriptor stride0");
PADDLE_ENFORCE_LE_INT_MAX(stride1, "cudnn tensor descriptor stride1");
PADDLE_ENFORCE_LE_INT_MAX(stride2, "cudnn tensor descriptor stride2");
dims = {1, NxC, H, W, D};
strides = {static_cast<int>(stride0),
static_cast<int>(stride1),
static_cast<int>(stride2),
D,
1};
#ifdef PADDLE_WITH_HIP
miopenTensorDescriptor_t data_desc_;
miopenTensorDescriptor_t in_param_desc_;
PADDLE_ENFORCE_GPU_SUCCESS(
phi::dynload::miopenCreateTensorDescriptor(&data_desc_));
PADDLE_ENFORCE_GPU_SUCCESS(
phi::dynload::miopenCreateTensorDescriptor(&in_param_desc_));
#else
cudnnTensorDescriptor_t data_desc_;
cudnnTensorDescriptor_t in_param_desc_;
PADDLE_ENFORCE_GPU_SUCCESS(
phi::dynload::cudnnCreateTensorDescriptor(&data_desc_));
PADDLE_ENFORCE_GPU_SUCCESS(
phi::dynload::cudnnCreateTensorDescriptor(&in_param_desc_));
#endif
if (epsilon <= CUDNN_BN_MIN_EPSILON - FLT_EPSILON) {
LOG(ERROR) << "Provided epsilon is smaller than "
<< "CUDNN_BN_MIN_EPSILON. Setting it to "
<< "CUDNN_BN_MIN_EPSILON instead.";
}
epsilon = std::max(epsilon, CUDNN_BN_MIN_EPSILON);
#ifdef PADDLE_WITH_HIP
PADDLE_ENFORCE_GPU_SUCCESS(phi::dynload::miopenSetTensorDescriptor(
data_desc_,
CudnnDataType<T>::type,
x_dims.size() > 3 ? x_dims.size() : 4,
const_cast<int *>(dims.data()),
const_cast<int *>(strides.data())));
PADDLE_ENFORCE_GPU_SUCCESS(phi::dynload::miopenDeriveBNTensorDescriptor(
in_param_desc_, data_desc_, miopenBNSpatial));
#else
PADDLE_ENFORCE_GPU_SUCCESS(phi::dynload::cudnnSetTensorNdDescriptor(
data_desc_,
CudnnDataType<T>::type,
x_dims.size() > 3 ? x_dims.size() : 4,
dims.data(),
strides.data()));
PADDLE_ENFORCE_GPU_SUCCESS(phi::dynload::cudnnDeriveBNTensorDescriptor(
in_param_desc_, data_desc_, CUDNN_BATCHNORM_SPATIAL));
#endif
const auto *saved_mean_data =
saved_mean.template data<BatchNormParamType<T>>();
const auto *saved_var_data =
saved_variance.template data<BatchNormParamType<T>>();
if (d_scale && d_bias) {
#ifdef PADDLE_WITH_HIP
PADDLE_ENFORCE_GPU_SUCCESS(phi::dynload::miopenBatchNormalizationBackward(
dev_ctx.cudnn_handle(),
miopenBNSpatial,
CudnnDataType<T>::kOne(),
CudnnDataType<T>::kZero(),
CudnnDataType<T>::kOne(),
CudnnDataType<T>::kZero(),
data_desc_,
x_tmp.template data<T>(),
data_desc_,
d_y_tmp.template data<T>(),
data_desc_,
d_x->template data<T>(),
in_param_desc_,
scale_tmp.template data<BatchNormParamType<T>>(),
d_scale_tmp.template data<BatchNormParamType<T>>(),
d_bias_tmp.template data<BatchNormParamType<T>>(),
epsilon,
saved_mean_data,
saved_var_data));
#else
PADDLE_ENFORCE_GPU_SUCCESS(phi::dynload::cudnnBatchNormalizationBackward(
dev_ctx.cudnn_handle(),
CUDNN_BATCHNORM_SPATIAL,
CudnnDataType<T>::kOne(),
CudnnDataType<T>::kZero(),
CudnnDataType<T>::kOne(),
CudnnDataType<T>::kZero(),
data_desc_,
x_tmp.template data<T>(),
data_desc_,
d_y_tmp.template data<T>(),
data_desc_,
d_x->template data<T>(),
in_param_desc_,
scale_tmp.template data<BatchNormParamType<T>>(),
d_scale_tmp.template data<BatchNormParamType<T>>(),
d_bias_tmp.template data<BatchNormParamType<T>>(),
epsilon,
saved_mean_data,
saved_var_data));
#endif
} else {
if (d_x) {
PADDLE_ENFORCE_LE_UINT32_MAX(NxC, "instance_norm_grad grid.x");
const uint32_t grid = static_cast<uint32_t>(NxC);
GradComputeDX<T, block><<<grid, block, 0, dev_ctx.stream()>>>(
d_y.data<T>(),
scale_tmp.data<BatchNormParamType<T>>(),
saved_mean_data,
x.data<T>(),
saved_var_data,
C,
sample_size_64,
d_x->data<T>());
}
}
if (d_scale && d_bias) {
add_param<AccT, block, false><<<grid1, block, 0, dev_ctx.stream()>>>(
d_scale_tmp.data<AccT>(), d_scale->data<AccT>(), N, C);
add_param<AccT, block, false><<<grid1, block, 0, dev_ctx.stream()>>>(
d_bias_tmp.data<AccT>(), d_bias->data<AccT>(), N, C);
}
#ifdef PADDLE_WITH_HIP
PADDLE_ENFORCE_GPU_SUCCESS(
phi::dynload::miopenDestroyTensorDescriptor(data_desc_));
PADDLE_ENFORCE_GPU_SUCCESS(
phi::dynload::miopenDestroyTensorDescriptor(in_param_desc_));
#else
PADDLE_ENFORCE_GPU_SUCCESS(
phi::dynload::cudnnDestroyTensorDescriptor(data_desc_));
PADDLE_ENFORCE_GPU_SUCCESS(
phi::dynload::cudnnDestroyTensorDescriptor(in_param_desc_));
#endif
}
template <typename T, typename Context>
void InstanceNormDoubleGradKernel(const Context &dev_ctx,
const DenseTensor &x,
const optional<DenseTensor> &scale,
const DenseTensor &saved_mean,
const DenseTensor &saved_variance,
const DenseTensor &dy,
const optional<DenseTensor> &ddx,
const optional<DenseTensor> &ddscale,
const optional<DenseTensor> &ddbias,
float epsilon_f,
DenseTensor *dx,
DenseTensor *dscale,
DenseTensor *ddy) {
using AccT = typename MPTypeTrait<T>::Type;
const auto *Scale = scale.get_ptr();
const auto *ddX = ddx.get_ptr();
const auto *ddScale = ddscale.get_ptr();
const auto *ddBias = ddbias.get_ptr();
const double epsilon = static_cast<double>(epsilon_f);
const T *x_data = x.data<T>();
const T *dy_data = dy.data<T>();
const T *ddx_data = (ddX == nullptr ? nullptr : ddX->data<T>());
const AccT *ddscale_data =
(ddScale == nullptr ? nullptr : ddScale->data<AccT>());
const AccT *ddbias_data =
(ddScale == nullptr ? nullptr : ddBias->data<AccT>());
const AccT *mean_data = saved_mean.data<AccT>();
const AccT *variance_data = saved_variance.data<AccT>();
funcs::SetConstant<GPUContext, T> set_zero;
funcs::SetConstant<GPUContext, AccT> set_zero_AccT;
auto &x_dims = x.dims();
int N, C, H, W, D;
funcs::ExtractNCWHD(x_dims, DataLayout::NCHW, &N, &C, &H, &W, &D);
const int64_t NxC_64 = static_cast<int64_t>(N) * C;
PADDLE_ENFORCE_LE_INT_MAX(NxC_64, "NxC");
const int NxC = static_cast<int>(NxC_64);
const int64_t n = x.numel();
int64_t sample_size = n / N / C;
DenseTensor scale_tmp;
if (!Scale) {
scale_tmp.Resize({C});
dev_ctx.template Alloc<AccT>(&scale_tmp);
set_zero_AccT(dev_ctx, &scale_tmp, static_cast<AccT>(1));
}
const AccT *scale_data = Scale ? Scale->data<AccT>() : scale_tmp.data<AccT>();
const int block = 512;
int max_threads = dev_ctx.GetMaxPhysicalThreadCount();
const int max_blocks = std::max(max_threads / block, 1);
const int grid = static_cast<int>(NxC);
const int grid1 = (C + block - 1) / block;
if (dx) {
T *dx_data = dev_ctx.template Alloc<T>(dx);
set_zero(dev_ctx, dx, static_cast<T>(0));
DoubleGradComputeDX<T, AccT, block>
<<<grid, block, 0, dev_ctx.stream()>>>(x_data,
mean_data,
variance_data,
ddx_data,
dy_data,
scale_data,
ddscale_data,
C,
sample_size,
epsilon,
dx_data);
}
if (dscale) {
DenseTensor dscale_tmp;
dscale_tmp.Resize({NxC});
dev_ctx.template Alloc<AccT>(&dscale_tmp);
set_zero_AccT(dev_ctx, &dscale_tmp, static_cast<AccT>(0));
AccT *dscale_tmp_data = dscale_tmp.data<AccT>();
AccT *dscale_data = dev_ctx.template Alloc<AccT>(dscale);
set_zero_AccT(dev_ctx, dscale, static_cast<AccT>(0));
DoubleGradComputeDScale<T, AccT, block>
<<<grid, block, 0, dev_ctx.stream()>>>(x_data,
mean_data,
variance_data,
ddx_data,
dy_data,
C,
sample_size,
epsilon,
dscale_tmp_data);
add_param<AccT, block, false><<<grid1, block, 0, dev_ctx.stream()>>>(
dscale_tmp.data<AccT>(), dscale->data<AccT>(), N, C);
}
if (ddy) {
T *ddy_data = dev_ctx.template Alloc<T>(ddy);
set_zero(dev_ctx, ddy, static_cast<T>(0));
DoubleGradComputeDDY<T, AccT, block>
<<<grid, block, 0, dev_ctx.stream()>>>(x_data,
mean_data,
variance_data,
ddscale_data,
ddbias_data,
ddx_data,
scale_data,
C,
sample_size,
epsilon,
ddy_data);
}
}
} // namespace phi
#ifdef PADDLE_WITH_HIP
// MIOPEN do not support double
PD_REGISTER_KERNEL(instance_norm_grad,
GPU,
ALL_LAYOUT,
phi::InstanceNormGradKernel,
float,
phi::float16) {}
PD_REGISTER_KERNEL(instance_norm_double_grad,
GPU,
ALL_LAYOUT,
phi::InstanceNormDoubleGradKernel,
float,
phi::float16) {}
#elif CUDNN_VERSION_MIN(8, 1, 0)
PD_REGISTER_KERNEL(instance_norm_grad,
GPU,
ALL_LAYOUT,
phi::InstanceNormGradKernel,
float,
double,
phi::float16,
phi::bfloat16) {}
PD_REGISTER_KERNEL(instance_norm_double_grad,
GPU,
ALL_LAYOUT,
phi::InstanceNormDoubleGradKernel,
float,
double,
phi::float16,
phi::bfloat16) {}
#else
PD_REGISTER_KERNEL(instance_norm_grad,
GPU,
ALL_LAYOUT,
phi::InstanceNormGradKernel,
float,
double,
phi::float16) {}
PD_REGISTER_KERNEL(instance_norm_double_grad,
GPU,
ALL_LAYOUT,
phi::InstanceNormDoubleGradKernel,
float,
double,
phi::float16) {}
#endif