[Fix] Clamp degenerate all-sentinel draft rows to token 0 in dspark _online_combine_kernel (#32277)
This commit is contained in:
@@ -143,7 +143,11 @@ def _online_combine_kernel(
|
|||||||
rescaled = tl.where(mask, rescaled, -1.0)
|
rescaled = tl.where(mask, rescaled, -1.0)
|
||||||
best = tl.max(rescaled, axis=0)
|
best = tl.max(rescaled, axis=0)
|
||||||
cand = tl.where(rescaled == best, idxs, _IDX_SENTINEL)
|
cand = tl.where(rescaled == best, idxs, _IDX_SENTINEL)
|
||||||
tl.store(next_tokens_ptr + row, tl.min(cand, axis=0).to(tl.int64))
|
next_token = tl.min(cand, axis=0)
|
||||||
|
# Degenerate rows (e.g. all -inf logits) leave cand all-sentinel; clamp to 0
|
||||||
|
# so a valid token id is emitted instead of an out-of-range 2147483647.
|
||||||
|
next_token = tl.where(next_token == _IDX_SENTINEL, 0, next_token)
|
||||||
|
tl.store(next_tokens_ptr + row, next_token.to(tl.int64))
|
||||||
|
|
||||||
|
|
||||||
def sample_step_tokens_triton(
|
def sample_step_tokens_triton(
|
||||||
|
|||||||
@@ -384,6 +384,10 @@ def compact_row_index_triton(
|
|||||||
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
||||||
verify_lens = verify_lens.to(device=device, dtype=torch.int64).contiguous()
|
verify_lens = verify_lens.to(device=device, dtype=torch.int64).contiguous()
|
||||||
bs = verify_lens.shape[0]
|
bs = verify_lens.shape[0]
|
||||||
|
# The search converges only for bs <= 2**(NBITS-1); beyond it silently mismaps.
|
||||||
|
assert bs <= 1 << (
|
||||||
|
_SEARCH_NBITS - 1
|
||||||
|
), f"bs={bs} exceeds row-index search capacity {1 << (_SEARCH_NBITS - 1)}"
|
||||||
incl = torch.cumsum(verify_lens, dim=0).contiguous()
|
incl = torch.cumsum(verify_lens, dim=0).contiguous()
|
||||||
req = torch.empty(padded_total, dtype=torch.int64, device=device)
|
req = torch.empty(padded_total, dtype=torch.int64, device=device)
|
||||||
within = torch.empty(padded_total, dtype=torch.int64, device=device)
|
within = torch.empty(padded_total, dtype=torch.int64, device=device)
|
||||||
|
|||||||
@@ -111,6 +111,8 @@ def speculative_sampling_classic_kernel(
|
|||||||
else:
|
else:
|
||||||
q_ptr = dp_base_ptr_safe + v_offsets * stride_dp_v
|
q_ptr = dp_base_ptr_safe + v_offsets * stride_dp_v
|
||||||
q_val = tl.load(q_ptr, mask=mask, other=0.0)
|
q_val = tl.load(q_ptr, mask=mask, other=0.0)
|
||||||
|
# Treat NaN q (degenerate draft rows) as 0: residual falls back to p.
|
||||||
|
q_val = tl.where(q_val == q_val, q_val, 0.0)
|
||||||
diff = p_val - q_val
|
diff = p_val - q_val
|
||||||
val = tl.where(diff > 0.0, diff, 0.0)
|
val = tl.where(diff > 0.0, diff, 0.0)
|
||||||
|
|
||||||
@@ -137,6 +139,8 @@ def speculative_sampling_classic_kernel(
|
|||||||
else:
|
else:
|
||||||
q_ptr = dp_base_ptr_safe + v_offsets * stride_dp_v
|
q_ptr = dp_base_ptr_safe + v_offsets * stride_dp_v
|
||||||
q_val = tl.load(q_ptr, mask=mask, other=0.0)
|
q_val = tl.load(q_ptr, mask=mask, other=0.0)
|
||||||
|
# Same NaN-q guard as pass 1.
|
||||||
|
q_val = tl.where(q_val == q_val, q_val, 0.0)
|
||||||
diff = p_val - q_val
|
diff = p_val - q_val
|
||||||
val = tl.where(diff > 0.0, diff, 0.0)
|
val = tl.where(diff > 0.0, diff, 0.0)
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ from sglang.srt.speculative.spec_info import (
|
|||||||
spec_scale_global_num_tokens,
|
spec_scale_global_num_tokens,
|
||||||
)
|
)
|
||||||
from sglang.srt.speculative.spec_utils import draft_tp_context
|
from sglang.srt.speculative.spec_utils import draft_tp_context
|
||||||
|
from sglang.srt.utils.async_probe import maybe_detect_nan
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -180,11 +181,13 @@ def sample_draft_block(
|
|||||||
if not any_sampling:
|
if not any_sampling:
|
||||||
|
|
||||||
def sampler(step_logits: torch.Tensor, step_idx: int) -> torch.Tensor:
|
def sampler(step_logits: torch.Tensor, step_idx: int) -> torch.Tensor:
|
||||||
|
maybe_detect_nan(step_logits, f"dspark draft step {step_idx}")
|
||||||
return torch.argmax(step_logits, dim=-1)
|
return torch.argmax(step_logits, dim=-1)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
def sampler(step_logits: torch.Tensor, step_idx: int) -> torch.Tensor:
|
def sampler(step_logits: torch.Tensor, step_idx: int) -> torch.Tensor:
|
||||||
|
maybe_detect_nan(step_logits, f"dspark draft step {step_idx}")
|
||||||
if fast_sampling:
|
if fast_sampling:
|
||||||
exp_noise = torch.empty(
|
exp_noise = torch.empty(
|
||||||
step_logits.shape, dtype=torch.float32, device=step_logits.device
|
step_logits.shape, dtype=torch.float32, device=step_logits.device
|
||||||
@@ -199,6 +202,11 @@ def sample_draft_block(
|
|||||||
probs = torch.softmax(
|
probs = torch.softmax(
|
||||||
step_logits.float() / temperatures[:, None], dim=-1
|
step_logits.float() / temperatures[:, None], dim=-1
|
||||||
)
|
)
|
||||||
|
# All-NaN rows make multinomial raise; clamp to one-hot token 0.
|
||||||
|
degenerate_rows = torch.isnan(probs[:, :1])
|
||||||
|
one_hot_token0 = torch.zeros_like(probs)
|
||||||
|
one_hot_token0[:, 0] = 1.0
|
||||||
|
probs = torch.where(degenerate_rows, one_hot_token0, probs)
|
||||||
argmax_tokens = torch.argmax(step_logits, dim=-1)
|
argmax_tokens = torch.argmax(step_logits, dim=-1)
|
||||||
sampled_tokens = torch.multinomial(probs, num_samples=1).squeeze(-1)
|
sampled_tokens = torch.multinomial(probs, num_samples=1).squeeze(-1)
|
||||||
return torch.where(greedy_mask, argmax_tokens, sampled_tokens)
|
return torch.where(greedy_mask, argmax_tokens, sampled_tokens)
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ from sglang.srt.speculative.dspark_components.dspark_planner import (
|
|||||||
apply_logits_adjustments_strided,
|
apply_logits_adjustments_strided,
|
||||||
)
|
)
|
||||||
from sglang.srt.speculative.ragged_verify import RaggedVerifyLayout
|
from sglang.srt.speculative.ragged_verify import RaggedVerifyLayout
|
||||||
|
from sglang.srt.utils.async_probe import maybe_detect_nan
|
||||||
|
|
||||||
|
|
||||||
def verify_logits_adjustments_are_noop(sampling_info) -> bool:
|
def verify_logits_adjustments_are_noop(sampling_info) -> bool:
|
||||||
@@ -677,6 +678,7 @@ def accept_draft_tokens(
|
|||||||
temperatures=draft_block.temperatures,
|
temperatures=draft_block.temperatures,
|
||||||
rows_per_request=gamma_rows,
|
rows_per_request=gamma_rows,
|
||||||
).view(bs, gamma_rows, vocab)
|
).view(bs, gamma_rows, vocab)
|
||||||
|
maybe_detect_nan(draft_probs, "dspark verify: draft_probs")
|
||||||
if not sampling_info.is_any_greedy:
|
if not sampling_info.is_any_greedy:
|
||||||
return AcceptSampling.execute(
|
return AcceptSampling.execute(
|
||||||
candidates=candidates,
|
candidates=candidates,
|
||||||
|
|||||||
Reference in New Issue
Block a user