// 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/impl/margin_cross_entropy.cu.h" namespace phi { template __global__ void CalculateGrad(T* logits_grad, const T* loss_grad, const T* logits, const IndexT* label, const float margin1, const float margin2, const float scale, const int rank, const int64_t N, const int64_t D, const int* class_interval_ptr) { using MT = typename MPTypeTrait::Type; int start_index = class_interval_ptr[rank]; CUDA_KERNEL_LOOP(i, N * D) { auto row = i / D; auto col = i % D; if ((col + start_index) == label[row]) { logits_grad[i] = (logits_grad[i] - static_cast(1.0)) * loss_grad[row]; if (fabs(margin1 - 1.0) > 1e-8 || fabs(margin2) > 1e-8) { MT dout = static_cast(logits_grad[i]); MT one = static_cast(1.0f); MT x = static_cast(logits[i]); MT m1 = static_cast(margin1); MT m2 = static_cast(margin2); MT d = m1 * sin(m1 * acos(x) + m2) / sqrt(one - x * x); logits_grad[i] = static_cast(dout * d); } } else { logits_grad[i] *= loss_grad[row]; } if (fabs(scale - 1.0) > 1e-8) { logits_grad[i] *= static_cast(scale); } } } template void MarginCrossEntropyGradKernel(const Context& dev_ctx, const DenseTensor& logits, const DenseTensor& label, const DenseTensor& softmax, const DenseTensor& loss_grad, bool return_softmax, int ring_id, int rank, int nranks, float margin1, float margin2, float margin3, float scale, DenseTensor* logits_grad) { const auto softmax_dims = softmax.dims(); const int axis = softmax_dims.size() - 1; const int64_t N = funcs::SizeToAxis(axis, softmax_dims); const int64_t D = funcs::SizeFromAxis(axis, softmax_dims); if (return_softmax) { Copy(dev_ctx, softmax, dev_ctx.GetPlace(), false, logits_grad); } else { logits_grad->ShareDataWith(softmax); } int64_t blocks = NumBlocks(N * D); int threads = kNumCUDAThreads; const auto& label_type = label.dtype(); DenseTensor class_interval; GetClassInterval(dev_ctx.stream(), dev_ctx.GetPlace(), dev_ctx, ring_id, rank, nranks, D, &class_interval); if (label_type == DataType::INT32) { typedef int32_t LabelT; CalculateGrad <<>>(logits_grad->data(), loss_grad.data(), logits.data(), label.data(), margin1, margin2, scale, rank, N, D, class_interval.data()); } else if (label_type == DataType::INT64) { typedef int64_t LabelT; CalculateGrad <<>>(logits_grad->data(), loss_grad.data(), logits.data(), label.data(), margin1, margin2, scale, rank, N, D, class_interval.data()); } } } // namespace phi PD_REGISTER_KERNEL(margin_cross_entropy_grad, GPU, ALL_LAYOUT, phi::MarginCrossEntropyGradKernel, float, double, phi::float16, phi::bfloat16) {}