Files
wehub-resource-sync 94057c3d3e
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:38:16 +08:00

863 lines
26 KiB
Python

from __future__ import annotations
from typing import Optional
import msgspec
import torch
import triton
import triton.language as tl
from sglang.srt.speculative.dflash_info_v2 import DFlashDraftInputV2
from sglang.srt.speculative.dflash_utils import (
_get_or_create_chain_verify_buffers,
build_dflash_verify_target_probs,
compute_dflash_correct_drafts_and_bonus,
)
from sglang.srt.speculative.dspark_components.kernels.dispatch import inputs_on_cuda
from sglang.srt.speculative.reject_sampling import chain_speculative_sampling_triton
class AcceptSampling:
@classmethod
def execute(
cls, *args, **kwargs
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
if inputs_on_cuda(*args, **kwargs):
return cls.triton(*args, **kwargs)
return cls.torch(*args, **kwargs)
@classmethod
def torch(
cls,
*,
candidates: torch.Tensor,
target_logits: torch.Tensor,
draft_probs: torch.Tensor,
sampling_info,
draft_input: DFlashDraftInputV2,
gamma: int,
verify_num_draft_tokens: int,
cutoff_verify_lens: Optional[torch.Tensor] = None,
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
return accept_sampling(
candidates=candidates,
target_logits=target_logits,
draft_probs=draft_probs,
sampling_info=sampling_info,
draft_input=draft_input,
gamma=gamma,
verify_num_draft_tokens=verify_num_draft_tokens,
cutoff_verify_lens=cutoff_verify_lens,
)
@classmethod
def triton(
cls,
*,
candidates: torch.Tensor,
target_logits: torch.Tensor,
draft_probs: torch.Tensor,
sampling_info,
draft_input: DFlashDraftInputV2,
gamma: int,
verify_num_draft_tokens: int,
cutoff_verify_lens: Optional[torch.Tensor] = None,
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
return accept_sampling_triton(
candidates=candidates,
target_logits=target_logits,
draft_probs=draft_probs,
sampling_info=sampling_info,
draft_input=draft_input,
gamma=gamma,
verify_num_draft_tokens=verify_num_draft_tokens,
cutoff_verify_lens=cutoff_verify_lens,
)
def _accept_sampling_core(
*,
candidates: torch.Tensor,
target_logits: torch.Tensor,
draft_probs: torch.Tensor,
sampling_info,
draft_input: DFlashDraftInputV2,
gamma: int,
verify_num_draft_tokens: int,
cutoff_verify_lens: Optional[torch.Tensor],
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
bs = candidates.shape[0]
device = candidates.device
if not sampling_info.need_top_k_sampling and not sampling_info.need_top_p_sampling:
target_probs = SoftmaxTemp.execute(
logits=target_logits,
temperatures=sampling_info.temperatures,
rows_per_request=verify_num_draft_tokens,
).view(bs, verify_num_draft_tokens, -1)
else:
target_probs = build_dflash_verify_target_probs(
next_token_logits=target_logits,
sampling_info=sampling_info,
draft_token_num=verify_num_draft_tokens,
bs=bs,
max_top_k=draft_input.max_top_k,
uniform_top_k_value=draft_input.uniform_top_k_value,
)
(
retrieve_index,
retrieve_next_token,
retrieve_next_sibling,
predicts,
accept_index,
accept_token_num,
) = _get_or_create_chain_verify_buffers(
bs=bs,
draft_token_num=verify_num_draft_tokens,
device=device,
)
uniform_samples = torch.rand((bs, gamma), dtype=torch.float32, device=device)
uniform_samples_final = torch.rand((bs,), dtype=torch.float32, device=device)
chain_speculative_sampling_triton(
predicts=predicts,
accept_index=accept_index,
accept_token_num=accept_token_num,
candidates=candidates,
retrive_index=retrieve_index,
retrive_next_token=retrieve_next_token,
retrive_next_sibling=retrieve_next_sibling,
uniform_samples=uniform_samples,
uniform_samples_for_final_sampling=uniform_samples_final,
target_probs=target_probs,
draft_probs=draft_probs,
threshold_single=1.0,
threshold_acc=1.0,
deterministic=True,
)
correct_len = accept_token_num
if cutoff_verify_lens is not None:
correct_len, cap_trim_lens = CapCorrectLen.execute(
correct_len=correct_len, verify_lens=cutoff_verify_lens
)
else:
cap_trim_lens = torch.zeros_like(correct_len)
return correct_len, cap_trim_lens, accept_index, predicts
def accept_sampling(
*,
candidates: torch.Tensor,
target_logits: torch.Tensor,
draft_probs: torch.Tensor,
sampling_info,
draft_input: DFlashDraftInputV2,
gamma: int,
verify_num_draft_tokens: int,
cutoff_verify_lens: Optional[torch.Tensor] = None,
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
bs = candidates.shape[0]
device = candidates.device
correct_len, cap_trim_lens, accept_index, predicts = _accept_sampling_core(
candidates=candidates,
target_logits=target_logits,
draft_probs=draft_probs,
sampling_info=sampling_info,
draft_input=draft_input,
gamma=gamma,
verify_num_draft_tokens=verify_num_draft_tokens,
cutoff_verify_lens=cutoff_verify_lens,
)
row_ids = torch.arange(bs, dtype=torch.long, device=device)
accept_pos = accept_index[row_ids, correct_len.to(torch.long)].to(torch.long)
bonus = predicts[accept_pos].to(torch.int64)
return correct_len, bonus, cap_trim_lens
@triton.jit
def _gather_two_level_bonus_kernel(
accept_index_ptr,
predicts_ptr,
correct_len_ptr,
out_ptr,
cols,
n,
BLOCK: tl.constexpr,
):
offs = tl.program_id(0) * BLOCK + tl.arange(0, BLOCK)
mask = offs < n
cl = tl.load(correct_len_ptr + offs, mask=mask, other=0).to(tl.int64)
accept_pos = tl.load(accept_index_ptr + offs * cols + cl, mask=mask, other=0).to(
tl.int64
)
bonus = tl.load(predicts_ptr + accept_pos, mask=mask, other=0)
tl.store(out_ptr + offs, bonus.to(tl.int64), mask=mask)
def gather_two_level_bonus_triton(
*,
accept_index: torch.Tensor,
predicts: torch.Tensor,
correct_len: torch.Tensor,
) -> torch.Tensor:
bs, cols = accept_index.shape
accept_index = accept_index.contiguous()
predicts = predicts.contiguous()
correct_len = correct_len.contiguous()
out = torch.empty(bs, dtype=torch.int64, device=accept_index.device)
BLOCK = 256
grid = (triton.cdiv(bs, BLOCK),)
_gather_two_level_bonus_kernel[grid](
accept_index, predicts, correct_len, out, cols, bs, BLOCK=BLOCK
)
return out
def accept_sampling_triton(
*,
candidates: torch.Tensor,
target_logits: torch.Tensor,
draft_probs: torch.Tensor,
sampling_info,
draft_input: DFlashDraftInputV2,
gamma: int,
verify_num_draft_tokens: int,
cutoff_verify_lens: Optional[torch.Tensor] = None,
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
correct_len, cap_trim_lens, accept_index, predicts = _accept_sampling_core(
candidates=candidates,
target_logits=target_logits,
draft_probs=draft_probs,
sampling_info=sampling_info,
draft_input=draft_input,
gamma=gamma,
verify_num_draft_tokens=verify_num_draft_tokens,
cutoff_verify_lens=cutoff_verify_lens,
)
bonus = gather_two_level_bonus_triton(
accept_index=accept_index, predicts=predicts, correct_len=correct_len
)
return correct_len, bonus, cap_trim_lens
try:
from flashinfer.sampling import softmax as _flashinfer_softmax
except ImportError:
_flashinfer_softmax = None
class SoftmaxTemp:
@classmethod
def execute(cls, *args, **kwargs) -> torch.Tensor:
if not inputs_on_cuda(*args, **kwargs):
return cls.torch(*args, **kwargs)
if _flashinfer_softmax is not None:
return cls.flashinfer(*args, **kwargs)
return cls.triton(*args, **kwargs)
@classmethod
def torch(
cls,
*,
logits: torch.Tensor,
temperatures: torch.Tensor,
rows_per_request: int,
) -> torch.Tensor:
return softmax_temp(
logits=logits,
temperatures=temperatures,
rows_per_request=rows_per_request,
)
@classmethod
def triton(
cls,
*,
logits: torch.Tensor,
temperatures: torch.Tensor,
rows_per_request: int,
) -> torch.Tensor:
return softmax_temp_triton(
logits=logits,
temperatures=temperatures,
rows_per_request=rows_per_request,
)
@classmethod
def flashinfer(
cls,
*,
logits: torch.Tensor,
temperatures: torch.Tensor,
rows_per_request: int,
) -> torch.Tensor:
return softmax_temp_flashinfer(
logits=logits,
temperatures=temperatures,
rows_per_request=rows_per_request,
)
def softmax_temp(
*,
logits: torch.Tensor,
temperatures: torch.Tensor,
rows_per_request: int,
) -> torch.Tensor:
num_rows = logits.shape[0]
bs = num_rows // rows_per_request
assert (
bs * rows_per_request == num_rows
), f"num_rows {num_rows} not divisible by rows_per_request {rows_per_request}"
temp_per_row = torch.repeat_interleave(
temperatures.reshape(bs).to(torch.float32), rows_per_request, dim=0
)
scaled = logits.to(torch.float32) / temp_per_row[:, None]
return torch.softmax(scaled, dim=-1)
@triton.jit
def _softmax_temp_kernel(
logits_ptr,
temp_ptr,
out_ptr,
vocab,
rows_per_request,
logits_row_stride,
BLOCK_V: tl.constexpr,
):
row = tl.program_id(0)
temp = tl.load(temp_ptr + row // rows_per_request).to(tl.float32)
base = logits_ptr + row.to(tl.int64) * logits_row_stride
out_base = out_ptr + row.to(tl.int64) * vocab
row_max = -float("inf")
for v0 in range(0, vocab, BLOCK_V):
offs = v0 + tl.arange(0, BLOCK_V)
vmask = offs < vocab
x = tl.load(base + offs, mask=vmask, other=-float("inf")).to(tl.float32)
x = x / temp
row_max = tl.maximum(row_max, tl.max(x, axis=0))
sum_exp = 0.0
for v0 in range(0, vocab, BLOCK_V):
offs = v0 + tl.arange(0, BLOCK_V)
vmask = offs < vocab
x = tl.load(base + offs, mask=vmask, other=-float("inf")).to(tl.float32)
x = x / temp
e = tl.exp(x - row_max)
e = tl.where(vmask, e, 0.0)
sum_exp += tl.sum(e, axis=0)
for v0 in range(0, vocab, BLOCK_V):
offs = v0 + tl.arange(0, BLOCK_V)
vmask = offs < vocab
x = tl.load(base + offs, mask=vmask, other=-float("inf")).to(tl.float32)
x = x / temp
e = tl.exp(x - row_max)
tl.store(out_base + offs, e / sum_exp, mask=vmask)
def softmax_temp_triton(
*,
logits: torch.Tensor,
temperatures: torch.Tensor,
rows_per_request: int,
) -> torch.Tensor:
num_rows, vocab = logits.shape[0], logits.shape[-1]
bs = num_rows // rows_per_request
assert (
bs * rows_per_request == num_rows
), f"num_rows {num_rows} not divisible by rows_per_request {rows_per_request}"
temperatures = temperatures.reshape(bs).to(torch.float32).contiguous()
out = torch.empty((num_rows, vocab), dtype=torch.float32, device=logits.device)
BLOCK_V = 4096
_softmax_temp_kernel[(num_rows,)](
logits,
temperatures,
out,
vocab,
rows_per_request,
logits.stride(0),
BLOCK_V=BLOCK_V,
)
return out
def softmax_temp_flashinfer(
*,
logits: torch.Tensor,
temperatures: torch.Tensor,
rows_per_request: int,
) -> torch.Tensor:
if _flashinfer_softmax is None:
raise RuntimeError(
"softmax_temp_flashinfer requires flashinfer.sampling.softmax, "
"which is unavailable in this environment"
)
num_rows, vocab = logits.shape[0], logits.shape[-1]
bs = num_rows // rows_per_request
assert (
bs * rows_per_request == num_rows
), f"num_rows {num_rows} not divisible by rows_per_request {rows_per_request}"
temp_per_row = torch.repeat_interleave(
temperatures.reshape(bs).to(torch.float32), rows_per_request, dim=0
).contiguous()
logits_2d = logits.to(torch.float32).contiguous()
return _flashinfer_softmax(logits=logits_2d, temperature=temp_per_row)
class MixedAcceptSelectResult(msgspec.Struct):
correct_len: torch.Tensor
bonus: torch.Tensor
cap_trim_lens: torch.Tensor
class SelectMixedAccept:
@classmethod
def execute(cls, *args, **kwargs) -> MixedAcceptSelectResult:
if inputs_on_cuda(*args, **kwargs):
return cls.triton(*args, **kwargs)
return cls.torch(*args, **kwargs)
@classmethod
def torch(
cls,
*,
greedy_mask: torch.Tensor,
greedy_len: torch.Tensor,
greedy_bonus: torch.Tensor,
greedy_trim: torch.Tensor,
sampling_len: torch.Tensor,
sampling_bonus: torch.Tensor,
sampling_trim: torch.Tensor,
) -> MixedAcceptSelectResult:
return select_mixed_accept(
greedy_mask=greedy_mask,
greedy_len=greedy_len,
greedy_bonus=greedy_bonus,
greedy_trim=greedy_trim,
sampling_len=sampling_len,
sampling_bonus=sampling_bonus,
sampling_trim=sampling_trim,
)
@classmethod
def triton(
cls,
*,
greedy_mask: torch.Tensor,
greedy_len: torch.Tensor,
greedy_bonus: torch.Tensor,
greedy_trim: torch.Tensor,
sampling_len: torch.Tensor,
sampling_bonus: torch.Tensor,
sampling_trim: torch.Tensor,
) -> MixedAcceptSelectResult:
return select_mixed_accept_triton(
greedy_mask=greedy_mask,
greedy_len=greedy_len,
greedy_bonus=greedy_bonus,
greedy_trim=greedy_trim,
sampling_len=sampling_len,
sampling_bonus=sampling_bonus,
sampling_trim=sampling_trim,
)
def select_mixed_accept(
*,
greedy_mask: torch.Tensor,
greedy_len: torch.Tensor,
greedy_bonus: torch.Tensor,
greedy_trim: torch.Tensor,
sampling_len: torch.Tensor,
sampling_bonus: torch.Tensor,
sampling_trim: torch.Tensor,
) -> MixedAcceptSelectResult:
correct_len = torch.where(
greedy_mask, greedy_len.to(sampling_len.dtype), sampling_len
)
bonus = torch.where(greedy_mask, greedy_bonus, sampling_bonus)
cap_trim_lens = torch.where(
greedy_mask, greedy_trim.to(sampling_trim.dtype), sampling_trim
)
return MixedAcceptSelectResult(
correct_len=correct_len, bonus=bonus, cap_trim_lens=cap_trim_lens
)
@triton.jit
def _mixed_accept_select_kernel(
greedy_mask_ptr,
greedy_len_ptr,
greedy_bonus_ptr,
greedy_trim_ptr,
sampling_len_ptr,
sampling_bonus_ptr,
sampling_trim_ptr,
correct_len_ptr,
bonus_ptr,
cap_trim_ptr,
bs,
BLOCK: tl.constexpr,
):
offs = tl.program_id(0) * BLOCK + tl.arange(0, BLOCK)
mask = offs < bs
is_greedy = tl.load(greedy_mask_ptr + offs, mask=mask, other=0) != 0
g_len = tl.load(greedy_len_ptr + offs, mask=mask, other=0)
s_len = tl.load(sampling_len_ptr + offs, mask=mask, other=0)
tl.store(correct_len_ptr + offs, tl.where(is_greedy, g_len, s_len), mask=mask)
g_bonus = tl.load(greedy_bonus_ptr + offs, mask=mask, other=0)
s_bonus = tl.load(sampling_bonus_ptr + offs, mask=mask, other=0)
tl.store(bonus_ptr + offs, tl.where(is_greedy, g_bonus, s_bonus), mask=mask)
g_trim = tl.load(greedy_trim_ptr + offs, mask=mask, other=0)
s_trim = tl.load(sampling_trim_ptr + offs, mask=mask, other=0)
tl.store(cap_trim_ptr + offs, tl.where(is_greedy, g_trim, s_trim), mask=mask)
def select_mixed_accept_triton(
*,
greedy_mask: torch.Tensor,
greedy_len: torch.Tensor,
greedy_bonus: torch.Tensor,
greedy_trim: torch.Tensor,
sampling_len: torch.Tensor,
sampling_bonus: torch.Tensor,
sampling_trim: torch.Tensor,
) -> MixedAcceptSelectResult:
bs = greedy_mask.shape[0]
device = greedy_mask.device
correct_len = torch.empty(bs, dtype=sampling_len.dtype, device=device)
bonus = torch.empty(bs, dtype=sampling_bonus.dtype, device=device)
cap_trim_lens = torch.empty(bs, dtype=sampling_trim.dtype, device=device)
BLOCK = 256
_mixed_accept_select_kernel[(triton.cdiv(bs, BLOCK),)](
greedy_mask,
greedy_len,
greedy_bonus,
greedy_trim,
sampling_len,
sampling_bonus,
sampling_trim,
correct_len,
bonus,
cap_trim_lens,
bs,
BLOCK=BLOCK,
)
return MixedAcceptSelectResult(
correct_len=correct_len, bonus=bonus, cap_trim_lens=cap_trim_lens
)
class AcceptGreedy:
@classmethod
def execute(
cls, *args, **kwargs
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
if inputs_on_cuda(*args, **kwargs):
return cls.triton(*args, **kwargs)
return cls.torch(*args, **kwargs)
@classmethod
def torch(
cls,
*,
candidates: torch.Tensor,
target_logits: torch.Tensor,
verify_num_draft_tokens: int,
cutoff_verify_lens: Optional[torch.Tensor] = None,
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
return accept_greedy(
candidates=candidates,
target_logits=target_logits,
verify_num_draft_tokens=verify_num_draft_tokens,
cutoff_verify_lens=cutoff_verify_lens,
)
@classmethod
def triton(
cls,
*,
candidates: torch.Tensor,
target_logits: torch.Tensor,
verify_num_draft_tokens: int,
cutoff_verify_lens: Optional[torch.Tensor] = None,
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
return accept_greedy_triton(
candidates=candidates,
target_logits=target_logits,
verify_num_draft_tokens=verify_num_draft_tokens,
cutoff_verify_lens=cutoff_verify_lens,
)
def accept_greedy(
*,
candidates: torch.Tensor,
target_logits: torch.Tensor,
verify_num_draft_tokens: int,
cutoff_verify_lens: Optional[torch.Tensor] = None,
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
bs = candidates.shape[0]
target_predict = torch.argmax(target_logits, dim=-1).view(
bs, verify_num_draft_tokens
)
correct_len, bonus = compute_dflash_correct_drafts_and_bonus(
candidates=candidates,
target_predict=target_predict,
)
cap_trim_lens = torch.zeros_like(correct_len)
if cutoff_verify_lens is not None:
correct_len, cap_trim_lens = CapCorrectLen.execute(
correct_len=correct_len, verify_lens=cutoff_verify_lens
)
row_ids = torch.arange(bs, device=target_predict.device)
bonus = target_predict[row_ids, correct_len.to(torch.long)].to(torch.int64)
return correct_len, bonus, cap_trim_lens
@triton.jit
def _gather_row_bonus_kernel(
table_ptr,
idx_ptr,
out_ptr,
cols,
n,
BLOCK: tl.constexpr,
):
offs = tl.program_id(0) * BLOCK + tl.arange(0, BLOCK)
mask = offs < n
idx = tl.load(idx_ptr + offs, mask=mask, other=0).to(tl.int64)
val = tl.load(table_ptr + offs * cols + idx, mask=mask, other=0)
tl.store(out_ptr + offs, val.to(tl.int64), mask=mask)
def gather_row_bonus_triton(*, table: torch.Tensor, idx: torch.Tensor) -> torch.Tensor:
bs, cols = table.shape
table = table.contiguous()
idx = idx.contiguous()
out = torch.empty(bs, dtype=torch.int64, device=table.device)
BLOCK = 256
grid = (triton.cdiv(bs, BLOCK),)
_gather_row_bonus_kernel[grid](table, idx, out, cols, bs, BLOCK=BLOCK)
return out
def accept_greedy_triton(
*,
candidates: torch.Tensor,
target_logits: torch.Tensor,
verify_num_draft_tokens: int,
cutoff_verify_lens: Optional[torch.Tensor] = None,
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
bs = candidates.shape[0]
target_predict = torch.argmax(target_logits, dim=-1).view(
bs, verify_num_draft_tokens
)
correct_len, bonus = compute_dflash_correct_drafts_and_bonus(
candidates=candidates,
target_predict=target_predict,
)
cap_trim_lens = torch.zeros_like(correct_len)
if cutoff_verify_lens is not None:
correct_len, cap_trim_lens = CapCorrectLen.execute(
correct_len=correct_len, verify_lens=cutoff_verify_lens
)
bonus = gather_row_bonus_triton(table=target_predict, idx=correct_len)
return correct_len, bonus, cap_trim_lens
class FinalizeAcceptLensResult(msgspec.Struct):
commit_lens: torch.Tensor
new_seq_lens: torch.Tensor
cap_trim_lens: torch.Tensor
class FinalizeAcceptLens:
@classmethod
def execute(cls, *args, **kwargs) -> FinalizeAcceptLensResult:
if inputs_on_cuda(*args, **kwargs):
return cls.triton(*args, **kwargs)
return cls.torch(*args, **kwargs)
@classmethod
def torch(
cls,
*,
correct_len: torch.Tensor,
cap_trim_lens: torch.Tensor,
prefix_lens: torch.Tensor,
) -> FinalizeAcceptLensResult:
return finalize_accept_lens(
correct_len=correct_len,
cap_trim_lens=cap_trim_lens,
prefix_lens=prefix_lens,
)
@classmethod
def triton(
cls,
*,
correct_len: torch.Tensor,
cap_trim_lens: torch.Tensor,
prefix_lens: torch.Tensor,
) -> FinalizeAcceptLensResult:
return finalize_accept_lens_triton(
correct_len=correct_len,
cap_trim_lens=cap_trim_lens,
prefix_lens=prefix_lens,
)
def finalize_accept_lens(
*,
correct_len: torch.Tensor,
cap_trim_lens: torch.Tensor,
prefix_lens: torch.Tensor,
) -> FinalizeAcceptLensResult:
commit_lens = correct_len.to(torch.int32) + 1
new_seq_lens = prefix_lens + commit_lens.to(prefix_lens.dtype)
return FinalizeAcceptLensResult(
commit_lens=commit_lens,
new_seq_lens=new_seq_lens,
cap_trim_lens=cap_trim_lens.to(torch.int32),
)
@triton.jit
def _finalize_accept_lens_kernel(
correct_len_ptr,
cap_trim_ptr,
prefix_lens_ptr,
commit_lens_ptr,
new_seq_lens_ptr,
cap_trim_out_ptr,
bs,
BLOCK: tl.constexpr,
):
offs = tl.program_id(0) * BLOCK + tl.arange(0, BLOCK)
mask = offs < bs
commit = tl.load(correct_len_ptr + offs, mask=mask, other=0).to(tl.int32) + 1
prefix = tl.load(prefix_lens_ptr + offs, mask=mask, other=0)
trim = tl.load(cap_trim_ptr + offs, mask=mask, other=0).to(tl.int32)
tl.store(commit_lens_ptr + offs, commit, mask=mask)
tl.store(new_seq_lens_ptr + offs, prefix + commit, mask=mask)
tl.store(cap_trim_out_ptr + offs, trim, mask=mask)
def finalize_accept_lens_triton(
*,
correct_len: torch.Tensor,
cap_trim_lens: torch.Tensor,
prefix_lens: torch.Tensor,
) -> FinalizeAcceptLensResult:
bs = correct_len.shape[0]
device = correct_len.device
commit_lens = torch.empty(bs, dtype=torch.int32, device=device)
new_seq_lens = torch.empty(bs, dtype=prefix_lens.dtype, device=device)
cap_trim_out = torch.empty(bs, dtype=torch.int32, device=device)
BLOCK = 256
_finalize_accept_lens_kernel[(triton.cdiv(bs, BLOCK),)](
correct_len,
cap_trim_lens,
prefix_lens,
commit_lens,
new_seq_lens,
cap_trim_out,
bs,
BLOCK=BLOCK,
)
return FinalizeAcceptLensResult(
commit_lens=commit_lens,
new_seq_lens=new_seq_lens,
cap_trim_lens=cap_trim_out,
)
class CapCorrectLen:
@classmethod
def execute(cls, *args, **kwargs) -> tuple[torch.Tensor, torch.Tensor]:
if inputs_on_cuda(*args, **kwargs):
return cls.triton(*args, **kwargs)
return cls.torch(*args, **kwargs)
@classmethod
def torch(
cls,
*,
correct_len: torch.Tensor,
verify_lens: torch.Tensor,
) -> tuple[torch.Tensor, torch.Tensor]:
return cap_correct_len(
correct_len=correct_len,
verify_lens=verify_lens,
)
@classmethod
def triton(
cls,
*,
correct_len: torch.Tensor,
verify_lens: torch.Tensor,
) -> tuple[torch.Tensor, torch.Tensor]:
return cap_correct_len_triton(
correct_len=correct_len,
verify_lens=verify_lens,
)
def cap_correct_len(
*,
correct_len: torch.Tensor,
verify_lens: torch.Tensor,
) -> tuple[torch.Tensor, torch.Tensor]:
ell_r = (verify_lens.to(device=correct_len.device) - 1).to(correct_len.dtype)
capped = torch.minimum(correct_len, ell_r)
cap_trim_lens = correct_len - capped
return capped, cap_trim_lens
@triton.jit
def _cap_correct_len_kernel(
correct_len_ptr,
verify_lens_ptr,
capped_ptr,
trim_ptr,
n,
BLOCK: tl.constexpr,
):
pid = tl.program_id(0)
offs = pid * BLOCK + tl.arange(0, BLOCK)
mask = offs < n
cl = tl.load(correct_len_ptr + offs, mask=mask, other=0).to(tl.int64)
vl = tl.load(verify_lens_ptr + offs, mask=mask, other=0).to(tl.int64)
ell = vl - 1
capped = tl.minimum(cl, ell)
trim = cl - capped
tl.store(capped_ptr + offs, capped, mask=mask)
tl.store(trim_ptr + offs, trim, mask=mask)
def cap_correct_len_triton(
*,
correct_len: torch.Tensor,
verify_lens: torch.Tensor,
) -> tuple[torch.Tensor, torch.Tensor]:
device = correct_len.device
correct_len = correct_len.contiguous()
verify_lens = verify_lens.to(device=device).contiguous()
n = correct_len.shape[0]
capped = torch.empty_like(correct_len)
trim = torch.empty_like(correct_len)
BLOCK = 1024
grid = (triton.cdiv(n, BLOCK),)
_cap_correct_len_kernel[grid](
correct_len, verify_lens, capped, trim, n, BLOCK=BLOCK
)
return capped, trim