Add customized sampler registration (#15423)

This commit is contained in:
Qiaolin Yu
2025-12-18 23:10:23 -08:00
committed by GitHub
parent f228b662a7
commit 173940927f
6 changed files with 60 additions and 11 deletions
+39 -1
View File
@@ -1,5 +1,5 @@
import logging import logging
from typing import List, Optional, Tuple from typing import Callable, Dict, List, Optional, Tuple
import torch import torch
import torch.distributed as dist import torch.distributed as dist
@@ -31,6 +31,8 @@ logger = logging.getLogger(__name__)
SYNC_TOKEN_IDS_ACROSS_TP = get_bool_env_var("SYNC_TOKEN_IDS_ACROSS_TP") SYNC_TOKEN_IDS_ACROSS_TP = get_bool_env_var("SYNC_TOKEN_IDS_ACROSS_TP")
SGLANG_RETURN_ORIGINAL_LOGPROB = get_bool_env_var("SGLANG_RETURN_ORIGINAL_LOGPROB") SGLANG_RETURN_ORIGINAL_LOGPROB = get_bool_env_var("SGLANG_RETURN_ORIGINAL_LOGPROB")
_CUSTOM_SAMPLER_FACTORIES: Dict[str, Callable[[], "Sampler"]] = {}
_BUILT_IN_SAMPLING_BACKENDS = {"flashinfer", "pytorch", "ascend"}
class Sampler(nn.Module): class Sampler(nn.Module):
@@ -268,6 +270,42 @@ class Sampler(nn.Module):
) = get_token_ids_logprobs_batch_optimized(logprobs, token_ids_logprobs) ) = get_token_ids_logprobs_batch_optimized(logprobs, token_ids_logprobs)
def register_sampler_backend(backend: str, factory: Callable[[], "Sampler"]) -> None:
"""Register a custom sampler factory for a backend string."""
if not backend:
raise ValueError("backend must be a non-empty string")
from sglang.srt.server_args import SAMPLING_BACKEND_CHOICES
if backend in _CUSTOM_SAMPLER_FACTORIES:
logger.warning("Overriding existing sampler factory for backend '%s'", backend)
SAMPLING_BACKEND_CHOICES.add(backend)
_CUSTOM_SAMPLER_FACTORIES[backend] = factory
def create_sampler(backend: Optional[str] = None) -> "Sampler":
"""Create a sampler honoring custom backend registrations."""
server_args = get_global_server_args()
backend = backend or (server_args.sampling_backend if server_args else None)
if backend in _CUSTOM_SAMPLER_FACTORIES:
sampler = _CUSTOM_SAMPLER_FACTORIES[backend]()
if not isinstance(sampler, Sampler):
raise TypeError(
f"Custom sampler factory for backend '{backend}' must return a Sampler"
)
return sampler
if backend is None or backend in _BUILT_IN_SAMPLING_BACKENDS:
return Sampler()
raise ValueError(
f"Unknown sampling backend '{backend}'. Register it via register_sampler_backend()."
)
def top_k_top_p_min_p_sampling_from_probs_torch( def top_k_top_p_min_p_sampling_from_probs_torch(
probs: torch.Tensor, probs: torch.Tensor,
top_ks: torch.Tensor, top_ks: torch.Tensor,
@@ -99,7 +99,7 @@ from sglang.srt.layers.dp_attention import (
from sglang.srt.layers.logits_processor import LogitsProcessorOutput from sglang.srt.layers.logits_processor import LogitsProcessorOutput
from sglang.srt.layers.pooler import EmbeddingPoolerOutput from sglang.srt.layers.pooler import EmbeddingPoolerOutput
from sglang.srt.layers.quantization.fp8_kernel import fp8_dtype from sglang.srt.layers.quantization.fp8_kernel import fp8_dtype
from sglang.srt.layers.sampler import Sampler from sglang.srt.layers.sampler import create_sampler
from sglang.srt.layers.torchao_utils import apply_torchao_config_to_model from sglang.srt.layers.torchao_utils import apply_torchao_config_to_model
from sglang.srt.lora.lora_manager import LoRAManager from sglang.srt.lora.lora_manager import LoRAManager
from sglang.srt.lora.lora_registry import LoRARef from sglang.srt.lora.lora_registry import LoRARef
@@ -451,7 +451,7 @@ class ModelRunner:
else None else None
) )
# Load the model # Load the model
self.sampler = Sampler() self.sampler = create_sampler()
self.load_model() self.load_model()
if ( if (
+2 -2
View File
@@ -40,7 +40,7 @@ from sglang.srt.layers.moe.topk import TopK
from sglang.srt.layers.quantization.base_config import QuantizationConfig from sglang.srt.layers.quantization.base_config import QuantizationConfig
from sglang.srt.layers.radix_attention import RadixAttention from sglang.srt.layers.radix_attention import RadixAttention
from sglang.srt.layers.rotary_embedding import get_rope from sglang.srt.layers.rotary_embedding import get_rope
from sglang.srt.layers.sampler import Sampler from sglang.srt.layers.sampler import create_sampler
from sglang.srt.layers.vocab_parallel_embedding import ( from sglang.srt.layers.vocab_parallel_embedding import (
ParallelLMHead, ParallelLMHead,
VocabParallelEmbedding, VocabParallelEmbedding,
@@ -603,7 +603,7 @@ class HunYuanMoEV1ForCausalLM(nn.Module):
logit_scale = getattr(config, "logit_scale", 1.0) logit_scale = getattr(config, "logit_scale", 1.0)
self.logits_processor = LogitsProcessor(config, logit_scale=logit_scale) self.logits_processor = LogitsProcessor(config, logit_scale=logit_scale)
self.sampler = Sampler() self.sampler = create_sampler()
def forward( def forward(
self, self,
@@ -89,8 +89,15 @@ class SamplingBatchInfo:
) )
sampling_seed = ( sampling_seed = (
torch.tensor( torch.tensor(
[r.sampling_params.sampling_seed for r in reqs], [
dtype=torch.int32, (
r.sampling_params.sampling_seed
if r.sampling_params.sampling_seed is not None
else 42
)
for r in reqs
],
dtype=torch.int64,
device=device, device=device,
) )
if enable_deterministic if enable_deterministic
@@ -173,8 +180,13 @@ class SamplingBatchInfo:
device=device, device=device,
logit_bias=logit_bias, logit_bias=logit_bias,
) )
ret.adjusted_from_schedule_batch(batch, vocab_size)
return ret return ret
# placeholder for override
def adjusted_from_schedule_batch(self, batch: ScheduleBatch, vocab_size: int):
pass
def __len__(self): def __len__(self):
return len(self.temperatures) return len(self.temperatures)
@@ -58,7 +58,7 @@ class SamplingParams:
custom_params: Optional[Dict[str, Any]] = None, custom_params: Optional[Dict[str, Any]] = None,
stream_interval: Optional[int] = None, stream_interval: Optional[int] = None,
logit_bias: Optional[Dict[str, float]] = None, logit_bias: Optional[Dict[str, float]] = None,
sampling_seed: int = 42, sampling_seed: Optional[int] = None,
) -> None: ) -> None:
self.max_new_tokens = max_new_tokens self.max_new_tokens = max_new_tokens
self.stop_strs = stop self.stop_strs = stop
@@ -146,8 +146,6 @@ class SamplingParams:
f"logit_bias must has keys in [0, {vocab_size - 1}], got " f"logit_bias must has keys in [0, {vocab_size - 1}], got "
f"{token_id}." f"{token_id}."
) )
if self.sampling_seed is None:
raise ValueError("sampling_seed should not be None")
grammars = [ grammars = [
self.json_schema, self.json_schema,
+2 -1
View File
@@ -70,6 +70,7 @@ logger = logging.getLogger(__name__)
# Define constants # Define constants
SAMPLING_BACKEND_CHOICES = {"flashinfer", "pytorch", "ascend"}
LOAD_FORMAT_CHOICES = [ LOAD_FORMAT_CHOICES = [
"auto", "auto",
"pt", "pt",
@@ -3220,7 +3221,7 @@ class ServerArgs:
parser.add_argument( parser.add_argument(
"--sampling-backend", "--sampling-backend",
type=str, type=str,
choices=["flashinfer", "pytorch", "ascend"], choices=SAMPLING_BACKEND_CHOICES,
default=ServerArgs.sampling_backend, default=ServerArgs.sampling_backend,
help="Choose the kernels for sampling layers.", help="Choose the kernels for sampling layers.",
) )