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

147 lines
5.3 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/sparse/fused_attention_grad_kernel.h"
#include "paddle/phi/backends/gpu/gpu_context.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/kernels/funcs/math_cuda_utils.h"
#include "paddle/phi/kernels/funcs/sparse/sparse_blas.h"
#include "paddle/phi/kernels/sparse/empty_kernel.h"
#include "paddle/phi/kernels/sparse/matmul_grad_kernel.h"
namespace phi {
namespace sparse {
template <typename T>
__global__ void AttnSoftmaxGpuGradKernel(const int64_t* out_crows,
const T* out_values,
const T* dout_values,
T* dx_values,
int M,
int total_row_num,
float scale,
int batch_nnz) {
// dx = (dout - sum(dout * out)) * out
int row = blockIdx.x * blockDim.y + threadIdx.y;
if (row >= total_row_num) return;
int cur_batch = row / M;
int crow_idx = cur_batch * (M + 1) + (row % M);
int row_first = cur_batch * batch_nnz + static_cast<int>(out_crows[crow_idx]);
int row_nnz = static_cast<int>(out_crows[crow_idx + 1] - out_crows[crow_idx]);
if (row_nnz == 0) return;
T mul = 0;
for (int idx = threadIdx.x; idx < row_nnz; idx += blockDim.x) {
mul += out_values[row_first + idx] * dout_values[row_first + idx];
}
T mul_sum = funcs::WarpReduceSum<T>(mul, 0xFFFFFFFF);
for (int idx = threadIdx.x; idx < row_nnz; idx += blockDim.x) {
dx_values[row_first + idx] = (dout_values[row_first + idx] - mul_sum) *
out_values[row_first + idx] / scale;
}
}
template <typename T, typename Context>
void FusedAttentionCsrGradKernel(const Context& dev_ctx,
const DenseTensor& query,
const DenseTensor& key,
const DenseTensor& value,
const SparseCsrTensor& softmax,
const DenseTensor& dout,
DenseTensor* dquery,
DenseTensor* dkey,
DenseTensor* dvalue) {
#if CUDA_VERSION >= 11080
/* Step1: Forward: softmax{CSR} * value{Dense} -> out{Dense}, reuse */
SparseCsrTensor dsoftmax;
MatmulCsrDenseGradKernel<T, Context>(
dev_ctx, softmax, value, dout, &dsoftmax, dvalue);
/* Step2: Calculate grad of sdd_result, manually not reuse */
SparseCsrTensor d_sdd_result;
EmptyLikeCsrKernel<T, Context>(dev_ctx, dsoftmax, &d_sdd_result);
auto q_dim = query.dims();
auto q_rank = q_dim.size();
int total_row_num = 1;
int batch_num = 1;
for (int i = 0; i < q_rank - 1; ++i) {
total_row_num *= q_dim[i];
if (i < q_rank - 2) {
batch_num *= q_dim[i];
}
}
int M = q_dim[q_rank - 2];
int N = q_dim[q_rank - 1];
int batch_nnz = softmax.nnz() / batch_num;
dim3 grid((total_row_num + 7) / 8);
dim3 block(WARP_SIZE, 8);
AttnSoftmaxGpuGradKernel<T><<<grid, block, 0, dev_ctx.stream()>>>(
softmax.crows().data<int64_t>(),
softmax.values().data<T>(),
dsoftmax.mutable_values()->data<T>(),
d_sdd_result.mutable_values()->data<T>(),
M,
total_row_num,
std::sqrt(N),
batch_nnz);
/* Step3: Forward: query{Dense} * key'{Dense} -> sdd_result{SparseCsr} */
auto sparse_blas = funcs::sparse::GetSparseBlas<Context, T>(dev_ctx);
// dquery{Dense} = d_sdd_result{SparseCsr} * key{Dense} //
dquery->Resize(query.dims());
dev_ctx.template Alloc<T>(dquery);
sparse_blas.SPMM(false,
false,
static_cast<T>(1.f),
d_sdd_result,
key,
static_cast<T>(0.f),
dquery);
// dkey{Dense} = d_sdd_result'{SparseCsr} * query{Dense} //
dkey->Resize(key.dims());
dev_ctx.template Alloc<T>(dkey);
sparse_blas.SPMM(true,
false,
static_cast<T>(1.f),
d_sdd_result,
query,
static_cast<T>(0.f),
dkey);
#else
PADDLE_THROW(common::errors::Unimplemented(
"backward of 'sparse.nn.functional.attention' "
"use 'cusparseCsrSetStridedBatch', which is "
"completed supported from CUDA 11.8"));
#endif
}
} // namespace sparse
} // namespace phi
PD_REGISTER_KERNEL(fused_attention_csr_grad,
GPU,
ALL_LAYOUT,
phi::sparse::FusedAttentionCsrGradKernel,
float,
double) {
kernel->InputAt(0).SetDataLayout(phi::DataLayout::SPARSE_CSR);
}