// 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/top_p_sampling_kernel.h" #include "xpu/refactor/customized_api.h" #include "paddle/phi/backends/xpu/enforce_xpu.h" #include "paddle/phi/common/memory_utils.h" #include "paddle/phi/core/kernel_registry.h" #include "paddle/phi/kernels/funcs/math_function.h" #include "paddle/common/flags.h" PHI_DEFINE_EXPORTED_bool(xpu_top_p_sampling_use_fp16, false, "use fp16 to improve the inference performance of " "top_p_sampling xpu kernel"); PHI_DEFINE_EXPORTED_bool(xpu_use_rejection_top_p_sampling, false, "use Dual Pivot Rejection Sampling to improve the " "inference performance of top_p_sampling. " "The algorithm performs better when top_p is larger. " "Note that top_p = 0 is not supported."); PHI_DEFINE_EXPORTED_int32( xpu_top_p_sampling_heuristic_threshold, 20, "threshold of heuristic method used for xpu_top_p_sampling, default 20; if " "heuristic_threshold = -1, xpu_top_p_sampling don't use heuristic method, " "and will fallback to normal top_p_sampling; if heuristic_threshold > 0, " "xpu_top_p_sampling will enable heuristic method"); namespace phi { template void TopPSamplingKernel(const Context& dev_ctx, const DenseTensor& x, const DenseTensor& ps, const optional& threshold, const optional& topp_seed, int64_t random_seed, int k, const std::string& mode, DenseTensor* out, DenseTensor* ids, DenseTensor* topk_scores, DenseTensor* topk_ids) { using XPUType = typename XPUTypeTrait::Type; const XPUType* x_ptr = reinterpret_cast(x.data()); const XPUType* ps_ptr = reinterpret_cast(ps.data()); XPUType* out_ptr = reinterpret_cast(dev_ctx.template Alloc(out)); int64_t* ids_ptr = dev_ctx.template Alloc(ids); auto x_dims = x.dims(); int64_t bs = x_dims[0]; int64_t vocab_size = x_dims[1]; XPUType* topk_scores_data = nullptr; int64_t* topk_ids_data = nullptr; if (k > 0) { topk_scores_data = reinterpret_cast(dev_ctx.template Alloc(topk_scores)); topk_ids_data = dev_ctx.template Alloc(topk_ids); int r = xpu::topk(dev_ctx.x_context(), x_ptr, topk_scores_data, topk_ids_data, {bs, vocab_size}, k, 1, true, true); PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu::topk"); } std::vector infer_seed(bs, random_seed); if (topp_seed.get_ptr() != nullptr) { TensorToVector(*topp_seed, dev_ctx, &infer_seed); } std::uniform_real_distribution dist(0.0, 1.0); std::vector rand_coeff_cpu; for (int64_t i = 0; i < bs; i++) { if (infer_seed[i] == -1) { std::shared_ptr engine = dev_ctx.GetGenerator()->GetCPUEngine(); rand_coeff_cpu.push_back(dist(*engine)); } else { std::mt19937_64 engine(infer_seed[i]); rand_coeff_cpu.push_back(dist(engine)); } } uint64_t seed_now = rand_coeff_cpu.empty() ? random_seed : rand_coeff_cpu[0]; uint64_t offset = 0; xpu::ctx_guard RAII_GUARD(dev_ctx.x_context()); int* ids_int_ptr = RAII_GUARD.alloc(ids->numel()); PADDLE_ENFORCE_EQ( threshold.is_initialized(), false, errors::InvalidArgument(("threshold not supported in top_p_sampling"))); if (!FLAGS_xpu_use_rejection_top_p_sampling) { float* rand_coeff_xpu = RAII_GUARD.alloc(rand_coeff_cpu.size()); int r = xpu::do_host2device(dev_ctx.x_context(), rand_coeff_cpu.data(), rand_coeff_xpu, rand_coeff_cpu.size() * sizeof(float)); PADDLE_ENFORCE_XDNN_SUCCESS(r, "do_host2device"); int heuristic_threshold = FLAGS_xpu_top_p_sampling_heuristic_threshold; if ((!FLAGS_xpu_top_p_sampling_use_fp16) || std::is_same::value) { r = xpu::faster_top_p_sampling(dev_ctx.x_context(), x_ptr, ps_ptr, rand_coeff_xpu, ids_int_ptr, bs, vocab_size, out_ptr, nullptr, heuristic_threshold); PADDLE_ENFORCE_XDNN_SUCCESS(r, "top_p_sampling"); } else { using XPUTypeFP16 = typename XPUTypeTrait::Type; XPUTypeFP16* x_fp16_ptr = RAII_GUARD.alloc(x.numel()); XPUTypeFP16* ps_fp16_ptr = RAII_GUARD.alloc(ps.numel()); XPUTypeFP16* out_fp16_ptr = RAII_GUARD.alloc(out->numel()); float fp16_scale = 32768.f; // experience value r = xpu::scale_cast_fusion( dev_ctx.x_context(), x_ptr, x_fp16_ptr, x.numel(), fp16_scale); PADDLE_ENFORCE_XDNN_SUCCESS(r, "scale_cast_fusion"); r = xpu::scale_cast_fusion( dev_ctx.x_context(), ps_ptr, ps_fp16_ptr, ps.numel(), fp16_scale); PADDLE_ENFORCE_XDNN_SUCCESS(r, "scale_cast_fusion"); r = xpu::faster_top_p_sampling(dev_ctx.x_context(), x_fp16_ptr, ps_fp16_ptr, rand_coeff_xpu, ids_int_ptr, bs, vocab_size, out_fp16_ptr, nullptr, heuristic_threshold); PADDLE_ENFORCE_XDNN_SUCCESS(r, "top_p_sampling"); r = xpu::scale_cast_fusion(dev_ctx.x_context(), out_fp16_ptr, out_ptr, out->numel(), 1.f / fp16_scale); PADDLE_ENFORCE_XDNN_SUCCESS(r, "scale_cast_fusion"); } } else { if ((!FLAGS_xpu_top_p_sampling_use_fp16) || std::is_same::value) { int r = xpu::top_k_top_p_sampling_from_probs( dev_ctx.x_context(), x_ptr, nullptr, ps_ptr, nullptr, ids_int_ptr, vocab_size, // top_k 1.0f, // top_p bs, vocab_size, true, seed_now, offset); PADDLE_ENFORCE_XDNN_SUCCESS( r, "xpu::top_k_top_p_sampling_from_probs::Type; XPUTypeFP16* x_fp16_ptr = RAII_GUARD.alloc(x.numel()); XPUTypeFP16* ps_fp16_ptr = RAII_GUARD.alloc(ps.numel()); float fp16_scale = 1.0f; // experience value int r = xpu::cast( dev_ctx.x_context(), x_ptr, x_fp16_ptr, x.numel()); PADDLE_ENFORCE_XDNN_SUCCESS(r, "scale_cast_fusion"); r = xpu::cast( dev_ctx.x_context(), ps_ptr, ps_fp16_ptr, ps.numel()); PADDLE_ENFORCE_XDNN_SUCCESS(r, "scale_cast_fusion"); r = xpu::top_k_top_p_sampling_from_probs( dev_ctx.x_context(), x_fp16_ptr, nullptr, ps_fp16_ptr, nullptr, ids_int_ptr, vocab_size, // top_k 1.0f, // top_p bs, vocab_size, true, seed_now, offset); PADDLE_ENFORCE_XDNN_SUCCESS( r, "xpu::top_k_top_p_sampling_from_probs(dev_ctx.x_context(), out_ptr, bs, 0); PADDLE_ENFORCE_XDNN_SUCCESS(r, "xpu::constant"); } int r = xpu::cast( dev_ctx.x_context(), ids_int_ptr, ids_ptr, ids->numel()); PADDLE_ENFORCE_XDNN_SUCCESS(r, "cast"); } } // namespace phi PD_REGISTER_KERNEL(top_p_sampling, XPU, ALL_LAYOUT, phi::TopPSamplingKernel, float, phi::float16) {}