[Ascend][Feat] Add Ascend sampling backend (#12692)

Co-authored-by: ronnie_zheng <zl19940307@163.com>
This commit is contained in:
Zhihao Lyu
2025-11-15 21:59:58 +08:00
committed by GitHub
parent 2aec8b6e1b
commit 10592e9c08
5 changed files with 165 additions and 4 deletions

View File

@@ -12,8 +12,9 @@ from sglang.srt.layers.dp_attention import (
)
from sglang.srt.layers.logits_processor import LogitsProcessorOutput
from sglang.srt.sampling.sampling_batch_info import SamplingBatchInfo
from sglang.srt.sampling.sampling_params import TOP_K_ALL
from sglang.srt.server_args import get_global_server_args
from sglang.srt.utils import crash_on_warnings, get_bool_env_var, is_cuda
from sglang.srt.utils import crash_on_warnings, get_bool_env_var, is_cuda, is_npu
if is_cuda():
from sgl_kernel import (
@@ -23,6 +24,8 @@ if is_cuda():
top_p_renorm_prob,
)
if is_npu():
import torch_npu
logger = logging.getLogger(__name__)
@@ -112,7 +115,11 @@ class Sampler(nn.Module):
# Post process logits
logits.div_(sampling_info.temperatures)
logits[:] = torch.softmax(logits, dim=-1)
# For ascend backend, softmax is not needed before sampling
if not get_global_server_args().sampling_backend == "ascend" or (
return_logprob and not SGLANG_RETURN_ORIGINAL_LOGPROB
):
logits[:] = torch.softmax(logits, dim=-1)
probs = logits
del logits
@@ -150,6 +157,14 @@ class Sampler(nn.Module):
sampling_info.sampling_seed,
positions,
)
elif get_global_server_args().sampling_backend == "ascend":
batch_next_token_ids = top_k_top_p_min_p_sampling_from_probs_ascend(
probs,
sampling_info.top_ks,
sampling_info.top_ps,
sampling_info.min_ps,
sampling_info.need_min_p_sampling,
)
else:
raise ValueError(
f"Invalid sampling backend: {get_global_server_args().sampling_backend}"
@@ -288,6 +303,55 @@ def top_k_top_p_min_p_sampling_from_probs_torch(
return batch_next_token_ids
def top_k_top_p_min_p_sampling_from_probs_ascend(
probs: torch.Tensor,
top_ks: torch.Tensor,
top_ps: torch.Tensor,
min_ps: torch.Tensor,
need_min_p_sampling: bool,
):
"""A top-k, top-p and min-p sampling implementation for ascend npu with torch_npu interface."""
# torch_npu.npu_top_k_top_p requires top_k value range in [1, 1024]
if hasattr(torch_npu, "npu_top_k_top_p") and torch.all(
(top_ks <= 1024) & (top_ks >= 1)
):
logits_top_k_top_p = torch_npu.npu_top_k_top_p(probs, top_ps, top_ks)
probs_top_k_top_p = logits_top_k_top_p.softmax(dim=-1)
if need_min_p_sampling:
min_p_thresholds = probs_top_k_top_p.max(dim=-1) * min_ps
min_p_mask = probs_top_k_top_p < min_p_thresholds.view(-1, 1)
probs_top_k_top_p.masked_fill_(min_p_mask, 0.0)
batch_next_token_ids = torch.multinomial(probs_top_k_top_p, num_samples=1)
else:
probs = torch.softmax(probs, dim=-1)
probs_sort, probs_idx = probs.sort(dim=-1, descending=True)
# when top_k is -1 (in which sglang turns it to TOP_K_ALL), make it explicitly equal to logit's size
topk_all_mask = top_ks == TOP_K_ALL
top_ks.masked_fill_(topk_all_mask, probs.shape[1])
top_k_mask = torch.arange(0, probs.shape[-1], device=probs.device).view(
1, -1
) >= top_ks.view(-1, 1)
probs_sort.masked_fill_(top_k_mask, 0.0)
probs_sum = torch.cumsum(probs_sort, dim=-1)
top_p_mask = probs_sum - probs_sort > top_ps.view(-1, 1)
probs_sort.masked_fill_(top_p_mask, 0.0)
if need_min_p_sampling:
min_p_thresholds = probs_sort[:, 0] * min_ps
min_p_mask = probs_sort < min_p_thresholds.view(-1, 1)
probs_sort.masked_fill_(min_p_mask, 0.0)
sampled_index = torch.multinomial(probs_sort, num_samples=1)
probs_idx = probs_idx.to(torch.int32)
batch_next_token_ids = torch.gather(probs_idx, dim=1, index=sampled_index)
return batch_next_token_ids.view(-1)
def multinomial_with_seed(
inputs: torch.Tensor, seed: torch.Tensor, positions: torch.Tensor
) -> torch.Tensor:

View File

@@ -2706,7 +2706,7 @@ class ServerArgs:
parser.add_argument(
"--sampling-backend",
type=str,
choices=["flashinfer", "pytorch"],
choices=["flashinfer", "pytorch", "ascend"],
default=ServerArgs.sampling_backend,
help="Choose the kernels for sampling layers.",
)