/* 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. */ #pragma once // CUDA and HIP use ReduceGpuKernel API #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) #include #include #include #include "paddle/phi/common/amp_type_traits.h" #include "paddle/phi/core/enforce.h" #include "paddle/phi/kernels/funcs/eigen/extensions.h" #include "paddle/phi/kernels/funcs/p_norm_utils.h" namespace phi { namespace kps { template struct SumOps { inline DEVICE MPType compute(MPType a, InT b) const { return reduce(a, static_cast(b)); } inline DEVICE MPType reduce(MPType a, MPType b) const { return a + b; } inline DEVICE OutT post_process(MPType a) const { return static_cast(a); } inline DEVICE MPType shfl_sync(unsigned mask, MPType data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } SumOps() {} }; namespace detail { template HOSTDEVICE inline bool IsNan(T val) { if constexpr (std::is_same_v || std::is_same_v) { return isnan(val); } if constexpr (std::is_same_v || std::is_same_v || std::is_same_v> || std::is_same_v>) { return phi::dtype::isnan(val); } return false; // int or bool } } // namespace detail template struct NansumOps { inline DEVICE MPType compute(MPType a, InT b) const { return reduce(a, static_cast(b)); } inline DEVICE MPType reduce(MPType a, MPType b) const { if (detail::IsNan(b)) return a; return a + b; } inline DEVICE OutT post_process(MPType a) const { return static_cast(a); } inline DEVICE MPType shfl_sync(unsigned mask, MPType data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } NansumOps() {} }; template struct ProdOps { inline DEVICE MPType compute(MPType a, InT b) const { return reduce(a, static_cast(b)); } inline DEVICE MPType reduce(MPType a, MPType b) const { return a * b; } inline DEVICE OutT post_process(MPType a) const { return static_cast(a); } inline DEVICE MPType shfl_sync(unsigned mask, MPType data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } ProdOps() {} }; template struct MeanOps { MPType factor; inline DEVICE MPType compute(MPType a, InT b) const { return reduce(a, static_cast(b)); } inline DEVICE MPType reduce(MPType a, MPType b) const { return a + b; } inline DEVICE OutT post_process(MPType a) const { return static_cast(a * factor); } inline DEVICE MPType shfl_sync(unsigned mask, MPType data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } explicit MeanOps(MPType factor) : factor(factor) {} }; template struct MinOps { inline DEVICE MPType compute(MPType a, InT b) const { return reduce(a, static_cast(b)); } inline DEVICE MPType reduce(MPType a, MPType b) const { if constexpr (std::is_floating_point::value) { if (isnan(a)) { return a; } if (isnan(b)) { return b; } } return (a < b ? a : b); } inline DEVICE OutT post_process(MPType a) const { return static_cast(a); } inline DEVICE MPType shfl_sync(unsigned mask, MPType data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } MinOps() {} }; template <> struct MinOps { inline DEVICE bool compute(bool a, bool b) const { return reduce(a, b); } inline DEVICE bool reduce(bool a, bool b) const { return a & b; } inline DEVICE bool post_process(bool a) const { return a; } #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) inline DEVICE bool shfl_sync(unsigned mask, bool data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } #endif MinOps() {} }; template struct MaxOps { MPType factor; inline DEVICE MPType compute(MPType a, InT b) const { return reduce(a, static_cast(b)); } inline DEVICE MPType reduce(MPType a, MPType b) const { if constexpr (std::is_floating_point::value) { if (isnan(a)) { return a; } if (isnan(b)) { return b; } } return (a > b ? a : b); } inline DEVICE OutT post_process(MPType a) const { return static_cast(a); } inline DEVICE MPType shfl_sync(unsigned mask, MPType data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } MaxOps() {} }; template <> struct MaxOps { inline DEVICE bool compute(bool a, bool b) const { return reduce(a, b); } inline DEVICE bool reduce(bool a, bool b) const { return a | b; } inline DEVICE bool post_process(bool a) const { return a; } #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) inline DEVICE bool shfl_sync(unsigned mask, bool data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } #endif MaxOps() {} }; template struct AbsMaxOps { inline DEVICE MPType compute(MPType a, InT b) const { MPType b_ = static_cast(inline_abs(b)); return reduce(a, b_); } inline DEVICE MPType reduce(MPType a, MPType b) const { if constexpr (std::is_floating_point::value) { if (isnan(a)) { return a; } if (isnan(b)) { return b; } } return (a > b ? a : b); } inline DEVICE OutT post_process(MPType a) const { return static_cast(a); } inline DEVICE MPType shfl_sync(unsigned mask, MPType data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } AbsMaxOps() {} }; template struct AbsMinOps { inline DEVICE MPType compute(MPType a, InT b) const { MPType b_ = static_cast(inline_abs(b)); return reduce(a, b_); } inline DEVICE MPType reduce(MPType a, MPType b) const { if constexpr (std::is_floating_point::value) { if (isnan(a)) { return a; } if (isnan(b)) { return b; } } return (a < b ? a : b); } inline DEVICE OutT post_process(MPType a) const { return static_cast(a); } inline DEVICE MPType shfl_sync(unsigned mask, MPType data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } AbsMinOps() {} }; template struct LogicalAndOps { inline DEVICE MPType compute(MPType a, InT b) const { return reduce(a, static_cast(b)); } inline DEVICE MPType reduce(MPType a, MPType b) const { return (b && a); } inline DEVICE OutT post_process(MPType a) const { return static_cast(a); } inline DEVICE MPType shfl_sync(unsigned mask, MPType data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } LogicalAndOps() {} }; template struct LogicalOrOps { inline DEVICE MPType compute(MPType a, InT b) const { return reduce(a, static_cast(b)); } inline DEVICE MPType reduce(MPType a, MPType b) const { return (b || a); } inline DEVICE OutT post_process(MPType a) const { return static_cast(a); } inline DEVICE MPType shfl_sync(unsigned mask, MPType data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } LogicalOrOps() {} }; template struct L0NormOps { inline DEVICE MPType compute(MPType a, InT b) const { MPType b_ = (b == static_cast(0)) ? static_cast(0) : static_cast(1); return reduce(a, b_); } inline DEVICE MPType reduce(MPType a, MPType b) const { return (a + b); } inline DEVICE OutT post_process(MPType a) const { return static_cast(a); } inline DEVICE MPType shfl_sync(unsigned mask, MPType data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } L0NormOps() {} }; template struct L1NormOps { inline DEVICE MPType compute(MPType a, InT b) const { MPType b_ = static_cast(inline_abs(b)); return reduce(a, b_); } inline DEVICE MPType reduce(MPType a, MPType b) const { return (a + b); } inline DEVICE OutT post_process(MPType a) const { return static_cast(a); } inline DEVICE MPType shfl_sync(unsigned mask, MPType data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } L1NormOps() {} }; template struct L2NormOps { inline DEVICE MPType compute(MPType a, InT b) const { MPType b_ = static_cast(b) * static_cast(b); return reduce(a, b_); } inline DEVICE MPType reduce(MPType a, MPType b) const { return (a + b); } inline DEVICE OutT post_process(MPType a) const { return static_cast(std::sqrt(a)); } inline DEVICE MPType shfl_sync(unsigned mask, MPType data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } L2NormOps() {} }; template struct SquaredL2NormOps { inline DEVICE MPType compute(MPType a, InT b) const { MPType b_ = static_cast(b) * static_cast(b); return reduce(a, b_); } inline DEVICE MPType reduce(MPType a, MPType b) const { return (a + b); } inline DEVICE OutT post_process(MPType a) const { return static_cast(a); } inline DEVICE MPType shfl_sync(unsigned mask, MPType data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } SquaredL2NormOps() {} }; template struct GenericPNormOps { MPType norm_; inline DEVICE MPType compute(MPType a, InT b) const { MPType b_ = std::pow(static_cast(inline_abs(b)), norm_); return reduce(a, b_); } inline DEVICE MPType reduce(MPType a, MPType b) const { return (a + b); } inline DEVICE OutT post_process(MPType a) const { return static_cast(std::pow(a, static_cast(1.0) / norm_)); } inline DEVICE MPType shfl_sync(unsigned mask, MPType data, int offset) const { return phi::backends::gpu::CudaShuffleDownSync(mask, data, offset); } explicit GenericPNormOps(MPType p_norm) : norm_(p_norm) {} }; } // namespace kps } // namespace phi #endif