diff --git a/paddle/phi/kernels/cpu/elementwise_kernel.cc b/paddle/phi/kernels/cpu/elementwise_kernel.cc index 0605b4846ae390..68a70aa2730522 100644 --- a/paddle/phi/kernels/cpu/elementwise_kernel.cc +++ b/paddle/phi/kernels/cpu/elementwise_kernel.cc @@ -106,6 +106,23 @@ void CopySignKernel(const Context& dev_ctx, } } +template +void NextafterKernel(const Context& dev_ctx, + const DenseTensor& x, + const DenseTensor& y, + DenseTensor* out) { + dev_ctx.template Alloc(out); + auto x_dims = x.dims(); + auto y_dims = y.dims(); + if (x_dims.size() >= y_dims.size()) { + funcs::ElementwiseCompute, T>( + dev_ctx, x, y, funcs ::NextafterFunctor(), out); + } else { + funcs::ElementwiseCompute, T>( + dev_ctx, x, y, funcs::InverseNextafterFunctor(), out); + } +} + } // namespace phi using complex64 = ::phi::dtype::complex; @@ -193,3 +210,5 @@ PD_REGISTER_KERNEL(copysign, double, phi::dtype::float16, phi::dtype::bfloat16) {} +PD_REGISTER_KERNEL( + nextafter, CPU, ALL_LAYOUT, phi::NextafterKernel, float, double) {} diff --git a/paddle/phi/kernels/cpu/nextafter_kernel.cc b/paddle/phi/kernels/cpu/nextafter_kernel.cc deleted file mode 100644 index ac4ab00a4d3fe9..00000000000000 --- a/paddle/phi/kernels/cpu/nextafter_kernel.cc +++ /dev/null @@ -1,22 +0,0 @@ -// 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/nextafter_kernel.h" - -#include "paddle/phi/backends/cpu/cpu_context.h" -#include "paddle/phi/core/kernel_registry.h" -#include "paddle/phi/kernels/impl/nextafter_kernel_impl.h" - -PD_REGISTER_KERNEL( - nextafter, CPU, ALL_LAYOUT, phi::NextafterKernel, float, double) {} diff --git a/paddle/phi/kernels/elementwise_kernel.h b/paddle/phi/kernels/elementwise_kernel.h index b8956803bdb6fb..7881c7a45fce4c 100644 --- a/paddle/phi/kernels/elementwise_kernel.h +++ b/paddle/phi/kernels/elementwise_kernel.h @@ -73,6 +73,12 @@ void CopySignKernel(const Context& dev_ctx, const DenseTensor& y, DenseTensor* out); +template +void NextafterKernel(const Context& dev_ctx, + const DenseTensor& x, + const DenseTensor& y, + DenseTensor* out); + template DenseTensor Maximum(const Context& dev_ctx, const DenseTensor& x, diff --git a/paddle/phi/kernels/funcs/elementwise_functor.h b/paddle/phi/kernels/funcs/elementwise_functor.h index 37ce9ca44d1244..2373d38925e474 100644 --- a/paddle/phi/kernels/funcs/elementwise_functor.h +++ b/paddle/phi/kernels/funcs/elementwise_functor.h @@ -1174,5 +1174,56 @@ struct InverseCopySignFunctor { } }; +template +struct NextafterFunctor { + inline HOSTDEVICE T operator()(const T x, const T y) const { + return static_cast( + std::nextafter(static_cast(x), static_cast(y))); + } +}; + +template +struct NextafterFunctor< + T, + typename std::enable_if_t::value>> { + inline HOSTDEVICE T operator()(const T x, const T y) const { + return std::nextafter(x, y); + } +}; + +template +struct NextafterFunctor::value>> { + inline HOSTDEVICE double operator()(const T x, const T y) const { + return std::nextafter(static_cast(x), static_cast(y)); + } +}; + +template +struct InverseNextafterFunctor { + inline HOSTDEVICE T operator()(const T x, const T y) const { + return static_cast( + std::nextafter(static_cast(y), static_cast(x))); + } +}; + +template +struct InverseNextafterFunctor< + T, + typename std::enable_if_t::value>> { + inline HOSTDEVICE T operator()(const T x, const T y) const { + return std::nextafter(y, x); + } +}; + +template +struct InverseNextafterFunctor< + T, + typename std::enable_if_t::value>> { + inline HOSTDEVICE double operator()(const T x, const T y) const { + return std::nextafter(static_cast(y), static_cast(x)); + } +}; + } // namespace funcs } // namespace phi diff --git a/paddle/phi/kernels/gpu/nextafter_kernel.cu b/paddle/phi/kernels/gpu/nextafter_kernel.cu deleted file mode 100644 index e0ac8212853c98..00000000000000 --- a/paddle/phi/kernels/gpu/nextafter_kernel.cu +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2021 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/nextafter_kernel.h" - -#include "paddle/phi/backends/gpu/gpu_context.h" -#include "paddle/phi/core/kernel_registry.h" -#include "paddle/phi/kernels/impl/nextafter_kernel_impl.h" - -PD_REGISTER_KERNEL( - nextafter, GPU, ALL_LAYOUT, phi::NextafterKernel, float, double) {} diff --git a/paddle/phi/kernels/impl/nextafter_kernel_impl.h b/paddle/phi/kernels/impl/nextafter_kernel_impl.h deleted file mode 100644 index e4ed11a6be5c66..00000000000000 --- a/paddle/phi/kernels/impl/nextafter_kernel_impl.h +++ /dev/null @@ -1,93 +0,0 @@ -/* 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. */ - -#pragma once -#include -#include "paddle/phi/core/dense_tensor.h" -#include "paddle/phi/core/device_context.h" -#include "paddle/phi/kernels/funcs/for_range.h" -#include "paddle/phi/kernels/funcs/math.h" -#include "paddle/phi/kernels/nextafter_kernel.h" -namespace phi { -template -struct NextafterOut { - using type = T; -}; - -template <> -struct NextafterOut { - using type = double; -}; - -template <> -struct NextafterOut { - using type = double; -}; -template -struct NextafterFunctor { - NextafterFunctor(const T* x, - const T* y, - typename NextafterOut::type* out, - int64_t numel) - : x_(x), y_(y), out_(out), numel_(numel) {} - - HOSTDEVICE void operator()(int64_t idx) const { - out_[idx] = static_cast::type>(std::nextafter( - static_cast(x_[idx]), static_cast(y_[idx]))); - } - const T* x_; - const T* y_; - typename NextafterOut::type* out_; - int64_t numel_; -}; -template <> -struct NextafterFunctor { - NextafterFunctor(const double* x, const double* y, double* out, int64_t numel) - : x_(x), y_(y), out_(out), numel_(numel) {} - - HOSTDEVICE void operator()(int64_t idx) const { - out_[idx] = std::nextafter(x_[idx], y_[idx]); - } - - const double* x_; - const double* y_; - double* out_; - int64_t numel_; -}; - -template -void NextafterKernel(const Context& ctx, - const DenseTensor& x, - const DenseTensor& y, - DenseTensor* out) { - auto* out_data = ctx.template Alloc(out); - auto x_data = x.data(); - auto y_data = y.data(); - auto x_numel = x.numel(); - - if (x.dims().size() != 0 && y.dims().size() != 0) { - PADDLE_ENFORCE_EQ( - x.dims(), - y.dims(), - errors::InvalidArgument( - "x and y must have same shape, but x.shape = %s, y.shape = %s.", - x.dims(), - y.dims())); - } - phi::funcs::ForRange for_range(ctx, x_numel); - phi::NextafterFunctor functor(x_data, y_data, out_data, x_numel); - for_range(functor); -} - -} // namespace phi diff --git a/paddle/phi/kernels/kps/elementwise_kernel.cu b/paddle/phi/kernels/kps/elementwise_kernel.cu index bb8d0d3bfd7500..5986df3b60ecec 100644 --- a/paddle/phi/kernels/kps/elementwise_kernel.cu +++ b/paddle/phi/kernels/kps/elementwise_kernel.cu @@ -196,6 +196,18 @@ void CopySignKernel(const Context& dev_ctx, dev_ctx, inputs, &outputs, funcs::CopySignFunctor()); } +template +void NextafterKernel(const Context& dev_ctx, + const DenseTensor& x, + const DenseTensor& y, + DenseTensor* out) { + std::vector inputs = {&x, &y}; + std::vector outputs = {out}; + dev_ctx.template Alloc(out); + funcs::BroadcastKernel( + dev_ctx, inputs, &outputs, funcs::NextafterFunctor()); +} + } // namespace phi #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) @@ -269,6 +281,8 @@ PD_REGISTER_KERNEL(copysign, double, phi::dtype::float16, phi::dtype::bfloat16) {} +PD_REGISTER_KERNEL( + nextafter, GPU, ALL_LAYOUT, phi::NextafterKernel, float, double) {} #endif diff --git a/paddle/phi/kernels/nextafter_kernel.h b/paddle/phi/kernels/nextafter_kernel.h deleted file mode 100644 index 3a185e39bd9407..00000000000000 --- a/paddle/phi/kernels/nextafter_kernel.h +++ /dev/null @@ -1,28 +0,0 @@ - -// 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. - -#pragma once - -#include "paddle/phi/core/dense_tensor.h" - -namespace phi { - -template -void NextafterKernel(const Context& dev_ctx, - const DenseTensor& x, - const DenseTensor& y, - DenseTensor* out); - -} // namespace phi diff --git a/test/legacy_test/test_nextafter_op.py b/test/legacy_test/test_nextafter_op.py index 872ff56304bbb7..6ea7d2327988bd 100644 --- a/test/legacy_test/test_nextafter_op.py +++ b/test/legacy_test/test_nextafter_op.py @@ -95,9 +95,10 @@ def setUp(self): self.op_type = "nextafter" self.python_api = paddle.nextafter self.init_dtype() + self.init_shape() - x = np.array([1, 2]).astype(self.dtype) - y = np.array([2, 1]).astype(self.dtype) + x = np.random.rand(*self.x_shape).astype(self.dtype) + y = np.random.rand(*self.y_shape).astype(self.dtype) out = np.nextafter(x, y) self.inputs = {'x': x, 'y': y} self.outputs = {'out': out} @@ -108,11 +109,45 @@ def test_check_output(self): def init_dtype(self): self.dtype = np.float64 + def init_shape(self): + self.x_shape = (2,) + self.y_shape = (2,) + class TestNextafterOPFP32(TestNextafterOP): def init_dtype(self): self.dtype = np.float32 +class TestNextafterOPFP32Case1(TestNextafterOP): + def init_dtype(self): + self.dtype = np.float32 + + def init_shape(self): + self.x_shape = (5,) + self.y_shape = (2, 3, 4, 5) + + +class TestNextafterOPFP32Case2(TestNextafterOP): + def init_dtype(self): + self.dtype = np.float32 + + def init_shape(self): + self.x_shape = (2, 3, 4, 5) + self.y_shape = (1,) + + +class TestNextafterOPCase1(TestNextafterOP): + def init_shape(self): + self.x_shape = (5,) + self.y_shape = (2, 3, 4, 5) + + +class TestNextafterOPCase2(TestNextafterOP): + def init_shape(self): + self.x_shape = (2, 3, 4, 5) + self.y_shape = (1,) + + if __name__ == "__main__": unittest.main()