[BugFix] Fix server crashes when req.grammar and ngram spec are enabled (#17585)
This commit is contained in:
@@ -7,6 +7,7 @@ from typing import Optional, Tuple
|
|||||||
import torch
|
import torch
|
||||||
import triton
|
import triton
|
||||||
|
|
||||||
|
from sglang.srt.constrained.base_grammar_backend import BaseGrammarObject
|
||||||
from sglang.srt.server_args import get_global_server_args
|
from sglang.srt.server_args import get_global_server_args
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -57,6 +58,7 @@ class NgramVerifyInput(SpecInput):
|
|||||||
retrive_next_token: torch.Tensor,
|
retrive_next_token: torch.Tensor,
|
||||||
retrive_next_sibling: torch.Tensor,
|
retrive_next_sibling: torch.Tensor,
|
||||||
draft_token_num: int,
|
draft_token_num: int,
|
||||||
|
grammar: BaseGrammarObject = None,
|
||||||
):
|
):
|
||||||
super().__init__(SpecInputType.NGRAM_VERIFY)
|
super().__init__(SpecInputType.NGRAM_VERIFY)
|
||||||
self.draft_token = draft_token
|
self.draft_token = draft_token
|
||||||
@@ -67,6 +69,7 @@ class NgramVerifyInput(SpecInput):
|
|||||||
self.retrive_next_sibling = retrive_next_sibling
|
self.retrive_next_sibling = retrive_next_sibling
|
||||||
self.draft_token_num = draft_token_num
|
self.draft_token_num = draft_token_num
|
||||||
self.device = self.custom_mask.device
|
self.device = self.custom_mask.device
|
||||||
|
self.grammar = grammar
|
||||||
|
|
||||||
def get_spec_adjust_token_coefficient(self) -> Tuple[int, int]:
|
def get_spec_adjust_token_coefficient(self) -> Tuple[int, int]:
|
||||||
return self.draft_token_num, self.draft_token_num
|
return self.draft_token_num, self.draft_token_num
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ from sglang.srt.server_args import ServerArgs
|
|||||||
from sglang.srt.speculative.cpp_ngram.ngram_cache import NgramCache
|
from sglang.srt.speculative.cpp_ngram.ngram_cache import NgramCache
|
||||||
from sglang.srt.speculative.ngram_info import NgramVerifyInput
|
from sglang.srt.speculative.ngram_info import NgramVerifyInput
|
||||||
from sglang.srt.speculative.spec_info import SpeculativeAlgorithm
|
from sglang.srt.speculative.spec_info import SpeculativeAlgorithm
|
||||||
|
from sglang.srt.speculative.spec_utils import generate_token_bitmask
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -213,10 +214,18 @@ class NGRAMWorker:
|
|||||||
def forward_batch_generation(self, batch: ScheduleBatch) -> GenerationBatchResult:
|
def forward_batch_generation(self, batch: ScheduleBatch) -> GenerationBatchResult:
|
||||||
self._prepare_for_speculative_decoding(batch)
|
self._prepare_for_speculative_decoding(batch)
|
||||||
model_worker_batch = batch.get_model_worker_batch()
|
model_worker_batch = batch.get_model_worker_batch()
|
||||||
|
spec_info = model_worker_batch.spec_info
|
||||||
num_accepted_tokens = 0
|
num_accepted_tokens = 0
|
||||||
accept_lens = None
|
accept_lens = None
|
||||||
|
|
||||||
if model_worker_batch.forward_mode.is_target_verify():
|
if model_worker_batch.forward_mode.is_target_verify():
|
||||||
|
if batch.has_grammar:
|
||||||
|
retrieve_next_token_cpu = spec_info.retrive_next_token.cpu()
|
||||||
|
retrieve_next_sibling_cpu = spec_info.retrive_next_sibling.cpu()
|
||||||
|
draft_tokens_cpu = spec_info.draft_token.view(
|
||||||
|
spec_info.retrive_next_token.shape
|
||||||
|
).cpu()
|
||||||
|
|
||||||
batch_result = self.target_worker.forward_batch_generation(
|
batch_result = self.target_worker.forward_batch_generation(
|
||||||
model_worker_batch, is_verify=True
|
model_worker_batch, is_verify=True
|
||||||
)
|
)
|
||||||
@@ -224,9 +233,30 @@ class NGRAMWorker:
|
|||||||
batch_result.logits_output,
|
batch_result.logits_output,
|
||||||
batch_result.can_run_cuda_graph,
|
batch_result.can_run_cuda_graph,
|
||||||
)
|
)
|
||||||
|
|
||||||
verify_input: NgramVerifyInput = model_worker_batch.spec_info
|
verify_input: NgramVerifyInput = model_worker_batch.spec_info
|
||||||
|
vocab_mask = None
|
||||||
|
if batch.has_grammar:
|
||||||
|
# Generate the logit mask for structured output.
|
||||||
|
# Overlap the CPU operations for bitmask generation with the forward pass.
|
||||||
|
vocab_mask = generate_token_bitmask(
|
||||||
|
batch.reqs,
|
||||||
|
verify_input,
|
||||||
|
retrieve_next_token_cpu,
|
||||||
|
retrieve_next_sibling_cpu,
|
||||||
|
draft_tokens_cpu,
|
||||||
|
batch.sampling_info.vocab_size,
|
||||||
|
)
|
||||||
|
|
||||||
|
if vocab_mask is not None:
|
||||||
|
assert verify_input.grammar is not None
|
||||||
|
vocab_mask = vocab_mask.to(verify_input.retrive_next_token.device)
|
||||||
|
# NOTE (sk): otherwise, this vocab mask will be the one from the previous extend stage
|
||||||
|
# and will be applied to produce wrong results
|
||||||
|
batch.sampling_info.vocab_mask = None
|
||||||
|
|
||||||
logits_output, next_token_ids, num_accepted_tokens = verify_input.verify(
|
logits_output, next_token_ids, num_accepted_tokens = verify_input.verify(
|
||||||
batch, logits_output, self.page_size
|
batch, logits_output, self.page_size, vocab_mask
|
||||||
)
|
)
|
||||||
# Store accept_lens for per-request metrics
|
# Store accept_lens for per-request metrics
|
||||||
accept_lens = verify_input.accept_length
|
accept_lens = verify_input.accept_length
|
||||||
|
|||||||
@@ -573,6 +573,7 @@ def traverse_tree(
|
|||||||
draft_tokens: torch.Tensor,
|
draft_tokens: torch.Tensor,
|
||||||
grammar: BaseGrammarObject,
|
grammar: BaseGrammarObject,
|
||||||
allocate_token_bitmask: torch.Tensor,
|
allocate_token_bitmask: torch.Tensor,
|
||||||
|
vocab_size: Optional[int] = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Traverse the tree constructed by the draft model to generate the logits mask.
|
Traverse the tree constructed by the draft model to generate the logits mask.
|
||||||
@@ -594,10 +595,13 @@ def traverse_tree(
|
|||||||
else:
|
else:
|
||||||
parent_bitmask = allocate_token_bitmask[parent_pos]
|
parent_bitmask = allocate_token_bitmask[parent_pos]
|
||||||
curr_token_id = draft_tokens[curr]
|
curr_token_id = draft_tokens[curr]
|
||||||
# 32 boolean bitmask values are packed into 32-bit integers
|
if vocab_size and curr_token_id >= vocab_size:
|
||||||
accepted = (
|
accepted = False
|
||||||
parent_bitmask[curr_token_id // 32] & (1 << (curr_token_id % 32))
|
else:
|
||||||
) != 0
|
# 32 boolean bitmask values are packed into 32-bit integers
|
||||||
|
accepted = (
|
||||||
|
parent_bitmask[curr_token_id // 32] & (1 << (curr_token_id % 32))
|
||||||
|
) != 0
|
||||||
|
|
||||||
if accepted:
|
if accepted:
|
||||||
if curr != 0:
|
if curr != 0:
|
||||||
@@ -670,6 +674,7 @@ def generate_token_bitmask(
|
|||||||
allocate_token_bitmask[
|
allocate_token_bitmask[
|
||||||
i * num_draft_tokens : (i + 1) * num_draft_tokens
|
i * num_draft_tokens : (i + 1) * num_draft_tokens
|
||||||
],
|
],
|
||||||
|
vocab_size=vocab_size,
|
||||||
)
|
)
|
||||||
tree_traverse_time = time.perf_counter() - s
|
tree_traverse_time = time.perf_counter() - s
|
||||||
if tree_traverse_time > TREE_TRAVERSE_TIME_THRESHOLD:
|
if tree_traverse_time > TREE_TRAVERSE_TIME_THRESHOLD:
|
||||||
|
|||||||
Reference in New Issue
Block a user