// 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/elementwise_add_kernel.h" #include #include #include "paddle/phi/api/ext/dispatch.h" #include "paddle/phi/backends/xpu/enforce_xpu.h" #include "paddle/phi/backends/xpu/xpu_context.h" #include "paddle/phi/backends/xpu/xpu_header.h" #include "paddle/phi/backends/xpu/xpu_info.h" #include "paddle/phi/core/kernel_registry.h" #include "paddle/phi/kernels/cast_kernel.h" #include "paddle/phi/kernels/complex_kernel.h" #include "paddle/phi/kernels/impl/elementwise_kernel_impl.h" #include "paddle/phi/kernels/xpu/elementwise.h" namespace phi { template void AddKernel(const Context& dev_ctx, const DenseTensor& x, const DenseTensor& y, DenseTensor* out) { if (x.dtype() == DataType::FLOAT32 && (y.dtype() == DataType::BFLOAT16 || y.dtype() == DataType::FLOAT16)) { // special case for "float32 + bfloat16", or "float32 + float16" if (out->numel() == 0) { dev_ctx.template Alloc(out); return; } auto dev_version = backends::xpu::get_xpu_version(dev_ctx.GetPlace().GetDeviceId()); if (dev_version >= backends::xpu::XPUVersion::XPU3 && x.dims() == y.dims()) { dev_ctx.template Alloc(out); const float* x_data = x.data(); float* z_data = out->data(); int ret = 0; if (y.dtype() == DataType::BFLOAT16) { using YType = DataTypeToCppType::type; using XPUYType = typename XPUTypeTrait::Type; auto y_data = reinterpret_cast(y.data()); ret = xpu::add_mul_type( dev_ctx.x_context(), x_data, y_data, z_data, x.numel()); } else { using YType = DataTypeToCppType::type; using XPUYType = typename XPUTypeTrait::Type; auto y_data = reinterpret_cast(y.data()); ret = xpu::add_mul_type( dev_ctx.x_context(), x_data, y_data, z_data, x.numel()); } PADDLE_ENFORCE_XDNN_SUCCESS(ret, "add_mul_type"); } else { using Type = DataTypeToCppType::type; using XPUType = typename XPUTypeTrait::Type; auto f = [](xpu::Context* xpu_ctx, const XPUType* x, const XPUType* y, XPUType* z, const std::vector& xshape, const std::vector& yshape) { return xpu::broadcast_add(xpu_ctx, x, y, z, xshape, yshape); }; auto casted_y = Cast(dev_ctx, y, DataType::FLOAT32); XPUElementwise(dev_ctx, x, casted_y, -1, out, f); } } else { if (out->numel() == 0) { dev_ctx.template Alloc(out); return; } using XPUType = typename XPUTypeTrait::Type; auto f = [](xpu::Context* xpu_ctx, const XPUType* x, const XPUType* y, XPUType* z, const std::vector& xshape, const std::vector& yshape) { return xpu::broadcast_add(xpu_ctx, x, y, z, xshape, yshape); }; XPUElementwise(dev_ctx, x, y, -1, out, f); } } template void GradAddXPUKernel(const Context& dev_ctx, const DenseTensor& x, const DenseTensor& y, DenseTensor* out) { using XPUType = typename XPUTypeTrait::Type; dev_ctx.template Alloc(out); auto x_shape = vectorize(x.dims()); auto y_shape = vectorize(y.dims()); int r = xpu::broadcast_add(dev_ctx.x_context(), reinterpret_cast(x.data()), reinterpret_cast(y.data()), reinterpret_cast(out->data()), x_shape, y_shape); PADDLE_ENFORCE_XDNN_SUCCESS(r, "broadcast_add"); } #ifdef PADDLE_WITH_XPU_FFT template <> void AddKernel(const XPUContext& dev_ctx, const DenseTensor& x, const DenseTensor& y, DenseTensor* out) { using T = phi::complex64; if (out->numel() == 0) { dev_ctx.template Alloc(out); return; } auto f = [](xpu::Context* xpu_ctx, const float* x, const float* y, float* z, const std::vector& xshape, const std::vector& yshape) { return xpu::broadcast_add(xpu_ctx, x, y, z, xshape, yshape); }; // The current complex number implementation uses separate real/imaginary // parts,resulting in redundant operations and performance // penalties.Optimization should address this in future iterations. const DenseTensor x_real = Real(dev_ctx, x); const DenseTensor x_imag = Imag(dev_ctx, x); const DenseTensor y_real = Real(dev_ctx, y); const DenseTensor y_imag = Imag(dev_ctx, y); DenseTensor real_out, imag_out; real_out.Resize(out->dims()); imag_out.Resize(out->dims()); dev_ctx.template Alloc(&real_out); dev_ctx.template Alloc(&imag_out); XPUElementwise(dev_ctx, x_real, y_real, -1, &real_out, f); XPUElementwise(dev_ctx, x_imag, y_imag, -1, &imag_out, f); phi::ComplexKernel(dev_ctx, real_out, imag_out, out); } #endif } // namespace phi PD_REGISTER_KERNEL( grad_add, XPU, ALL_LAYOUT, phi::GradAddXPUKernel, phi::float16, float) {} PD_REGISTER_KERNEL(add, XPU, ALL_LAYOUT, phi::AddKernel, double, phi::float16, phi::bfloat16, #ifdef PADDLE_WITH_XPU_FFT phi::complex64, #endif float, int, int64_t) { }