[Fix] Keep deterministic GDN prefill on Triton (#35632)
This commit is contained in:
@@ -11,6 +11,7 @@ from sglang.srt.configs.hybrid_arch import hybrid_gdn_config
|
|||||||
from sglang.srt.layers.attention.hybrid_linear_attn_backend import MambaAttnBackendBase
|
from sglang.srt.layers.attention.hybrid_linear_attn_backend import MambaAttnBackendBase
|
||||||
from sglang.srt.layers.attention.linear.kernels.gdn_triton import TritonGDNKernel
|
from sglang.srt.layers.attention.linear.kernels.gdn_triton import TritonGDNKernel
|
||||||
from sglang.srt.layers.attention.linear.utils import (
|
from sglang.srt.layers.attention.linear.utils import (
|
||||||
|
LinearAttnBackends,
|
||||||
LinearAttnKernelBackend,
|
LinearAttnKernelBackend,
|
||||||
build_verify_intermediate_state_indices,
|
build_verify_intermediate_state_indices,
|
||||||
)
|
)
|
||||||
@@ -71,6 +72,7 @@ def flashinfer_gdn_prefill_default(model_runner: ModelRunner) -> Optional[str]:
|
|||||||
if (
|
if (
|
||||||
get_exec().mamba.linear_attn_prefill_backend is not None
|
get_exec().mamba.linear_attn_prefill_backend is not None
|
||||||
or get_exec().mamba.linear_attn_backend != "triton"
|
or get_exec().mamba.linear_attn_backend != "triton"
|
||||||
|
or get_exec().deterministic.enable_deterministic_inference
|
||||||
or get_memory().enable_page_major_kv_layout
|
or get_memory().enable_page_major_kv_layout
|
||||||
or sm_major not in (9, 10)
|
or sm_major not in (9, 10)
|
||||||
):
|
):
|
||||||
@@ -113,6 +115,18 @@ def flashinfer_gdn_prefill_default(model_runner: ModelRunner) -> Optional[str]:
|
|||||||
return "flashinfer"
|
return "flashinfer"
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_gdn_linear_attn_backends(backends: LinearAttnBackends) -> None:
|
||||||
|
if (
|
||||||
|
get_exec().deterministic.enable_deterministic_inference
|
||||||
|
and backends.prefill.is_flashinfer()
|
||||||
|
):
|
||||||
|
raise ValueError(
|
||||||
|
"FlashInfer GDN prefill is not supported with "
|
||||||
|
"--enable-deterministic-inference. Use "
|
||||||
|
"--linear-attn-prefill-backend triton."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class GDNKernelDispatcher:
|
class GDNKernelDispatcher:
|
||||||
"""Dispatches GDN kernel calls to the appropriate backend per mode."""
|
"""Dispatches GDN kernel calls to the appropriate backend per mode."""
|
||||||
|
|
||||||
@@ -359,6 +373,7 @@ class GDNAttnBackend(MambaAttnBackendBase):
|
|||||||
needs_cpu_seq_lens: bool = False
|
needs_cpu_seq_lens: bool = False
|
||||||
|
|
||||||
def __init__(self, model_runner: ModelRunner):
|
def __init__(self, model_runner: ModelRunner):
|
||||||
|
_validate_gdn_linear_attn_backends(model_runner.linear_attn_backends)
|
||||||
super().__init__(model_runner)
|
super().__init__(model_runner)
|
||||||
self.conv_states_shape = (
|
self.conv_states_shape = (
|
||||||
model_runner.req_to_token_pool.mamba_pool.mamba_cache.conv[0].shape
|
model_runner.req_to_token_pool.mamba_pool.mamba_cache.conv[0].shape
|
||||||
|
|||||||
@@ -11,15 +11,20 @@ from sglang.srt.layers.attention.linear import gdn_backend
|
|||||||
from sglang.srt.layers.attention.linear.gdn_backend import (
|
from sglang.srt.layers.attention.linear.gdn_backend import (
|
||||||
GDNAttnBackend,
|
GDNAttnBackend,
|
||||||
GDNKernelDispatcher,
|
GDNKernelDispatcher,
|
||||||
|
_validate_gdn_linear_attn_backends,
|
||||||
flashinfer_gdn_prefill_default,
|
flashinfer_gdn_prefill_default,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.attention.linear.kernels.gdn_flashinfer import (
|
from sglang.srt.layers.attention.linear.kernels.gdn_flashinfer import (
|
||||||
maybe_build_flashinfer_checkpoint_plan,
|
maybe_build_flashinfer_checkpoint_plan,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.attention.linear.kernels.gdn_triton import TritonGDNKernel
|
from sglang.srt.layers.attention.linear.kernels.gdn_triton import TritonGDNKernel
|
||||||
from sglang.srt.layers.attention.linear.utils import LinearAttnKernelBackend
|
from sglang.srt.layers.attention.linear.utils import (
|
||||||
|
LinearAttnKernelBackend,
|
||||||
|
resolve_linear_attn_backends,
|
||||||
|
)
|
||||||
from sglang.srt.runtime_context import get_context
|
from sglang.srt.runtime_context import get_context
|
||||||
from sglang.test.ci.ci_register import register_cpu_ci
|
from sglang.test.ci.ci_register import register_cpu_ci
|
||||||
|
from sglang.test.test_utils import CustomTestCase
|
||||||
|
|
||||||
register_cpu_ci(est_time=5, suite="base-a-test-cpu")
|
register_cpu_ci(est_time=5, suite="base-a-test-cpu")
|
||||||
|
|
||||||
@@ -73,7 +78,7 @@ def make_runner(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestFlashInferGDNPrefillBackendPolicy(unittest.TestCase):
|
class TestFlashInferGDNPrefillBackendPolicy(CustomTestCase):
|
||||||
def apply_policy(
|
def apply_policy(
|
||||||
self,
|
self,
|
||||||
runner,
|
runner,
|
||||||
@@ -119,6 +124,44 @@ class TestFlashInferGDNPrefillBackendPolicy(unittest.TestCase):
|
|||||||
runner = make_runner(self, linear_attn_prefill_backend=backend)
|
runner = make_runner(self, linear_attn_prefill_backend=backend)
|
||||||
self.assertIsNone(self.apply_policy(runner))
|
self.assertIsNone(self.apply_policy(runner))
|
||||||
|
|
||||||
|
def test_declines_when_deterministic_inference_is_enabled(self):
|
||||||
|
"""Batch-sensitive GDN prefill must not bypass deterministic inference."""
|
||||||
|
runner = make_runner(
|
||||||
|
self,
|
||||||
|
state_dtype=torch.float32,
|
||||||
|
enable_deterministic_inference=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertIsNone(
|
||||||
|
self.apply_policy(
|
||||||
|
runner,
|
||||||
|
capability=(9, 0),
|
||||||
|
cuda_version="12.9",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_rejects_explicit_flashinfer_prefill_in_deterministic_mode(self):
|
||||||
|
"""Explicit backend precedence must not bypass deterministic GDN startup."""
|
||||||
|
cases = (
|
||||||
|
{"linear_attn_prefill_backend": "flashinfer"},
|
||||||
|
{"linear_attn_backend": "flashinfer"},
|
||||||
|
)
|
||||||
|
for fields in cases:
|
||||||
|
with self.subTest(fields=fields):
|
||||||
|
make_runner(
|
||||||
|
self,
|
||||||
|
enable_deterministic_inference=True,
|
||||||
|
**fields,
|
||||||
|
)
|
||||||
|
backends = resolve_linear_attn_backends()
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
ValueError,
|
||||||
|
"FlashInfer GDN prefill is not supported with "
|
||||||
|
"--enable-deterministic-inference",
|
||||||
|
):
|
||||||
|
_validate_gdn_linear_attn_backends(backends)
|
||||||
|
|
||||||
def test_rejects_unsupported_capability(self):
|
def test_rejects_unsupported_capability(self):
|
||||||
cases = (
|
cases = (
|
||||||
("non_cuda", {}, {"cuda": False}),
|
("non_cuda", {}, {"cuda": False}),
|
||||||
|
|||||||
Reference in New Issue
Block a user