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
863 lines
26 KiB
Python
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
|