Add intel_xpu to DETERMINISTIC_ATTENTION_BACKEND_CHOICES (#29143)
Co-authored-by: vshekhawat-hlab <vshekhawat@habana.ai>
This commit is contained in:
co-authored by
vshekhawat-hlab
parent
fee00a41db
commit
4c02584773
@@ -99,6 +99,15 @@ class XPUAttentionBackend(AttentionBackend):
|
|||||||
self.has_swa = (
|
self.has_swa = (
|
||||||
self.sliding_window_size is not None and self.sliding_window_size > -1
|
self.sliding_window_size is not None and self.sliding_window_size > -1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# If num_splits == 0, the kernel uses a heuristic to automatically
|
||||||
|
# determine the number of splits. Split-KV reduces across a
|
||||||
|
# non-deterministic number of partitions, so we pin num_splits to 1
|
||||||
|
# when deterministic inference is enabled to keep attention reduction
|
||||||
|
# order fixed. This mirrors the flash-attention (fa3) backend.
|
||||||
|
self.num_splits = (
|
||||||
|
1 if model_runner.server_args.enable_deterministic_inference else 0
|
||||||
|
)
|
||||||
self.is_encoder_decoder = model_runner.model_config.is_encoder_decoder
|
self.is_encoder_decoder = model_runner.model_config.is_encoder_decoder
|
||||||
|
|
||||||
def init_forward_metadata(self, forward_batch: ForwardBatch):
|
def init_forward_metadata(self, forward_batch: ForwardBatch):
|
||||||
@@ -553,6 +562,10 @@ class XPUAttentionBackend(AttentionBackend):
|
|||||||
# Use Flash Attention for prefill
|
# Use Flash Attention for prefill
|
||||||
if not self.use_mla:
|
if not self.use_mla:
|
||||||
# Do multi-head attention
|
# Do multi-head attention
|
||||||
|
# The MLA branch passes num_splits explicitly per call site, since the
|
||||||
|
# chunked-prefix varlen kernels there keep their own default.
|
||||||
|
kwargs["num_splits"] = self.num_splits
|
||||||
|
|
||||||
key_cache, value_cache = self.token_to_kv_pool.get_kv_buffer(layer.layer_id)
|
key_cache, value_cache = self.token_to_kv_pool.get_kv_buffer(layer.layer_id)
|
||||||
key_cache = key_cache.view(
|
key_cache = key_cache.view(
|
||||||
-1, self.page_size, layer.tp_k_head_num, layer.head_dim
|
-1, self.page_size, layer.tp_k_head_num, layer.head_dim
|
||||||
@@ -716,6 +729,7 @@ class XPUAttentionBackend(AttentionBackend):
|
|||||||
k_descale=k_descale,
|
k_descale=k_descale,
|
||||||
v_descale=v_descale,
|
v_descale=v_descale,
|
||||||
return_softmax_lse=use_cascade_attn,
|
return_softmax_lse=use_cascade_attn,
|
||||||
|
num_splits=self.num_splits,
|
||||||
)
|
)
|
||||||
if use_cascade_attn:
|
if use_cascade_attn:
|
||||||
o, softmax_lse, *rest = result
|
o, softmax_lse, *rest = result
|
||||||
@@ -737,6 +751,7 @@ class XPUAttentionBackend(AttentionBackend):
|
|||||||
k_descale=k_descale,
|
k_descale=k_descale,
|
||||||
v_descale=v_descale,
|
v_descale=v_descale,
|
||||||
return_softmax_lse=True,
|
return_softmax_lse=True,
|
||||||
|
num_splits=self.num_splits,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
o, _ = merge_state_v2_wrapper(
|
o, _ = merge_state_v2_wrapper(
|
||||||
@@ -843,6 +858,11 @@ class XPUAttentionBackend(AttentionBackend):
|
|||||||
if not self.use_mla:
|
if not self.use_mla:
|
||||||
# Do multi-head attention
|
# Do multi-head attention
|
||||||
|
|
||||||
|
# Only the MHA kernels below take num_splits. The MLA path calls
|
||||||
|
# flash_mla_decode, whose own num_kv_splits already defaults to 1
|
||||||
|
# (no split-KV), so it needs no deterministic override here.
|
||||||
|
kwargs["num_splits"] = self.num_splits
|
||||||
|
|
||||||
key_cache, value_cache = self.token_to_kv_pool.get_kv_buffer(layer.layer_id)
|
key_cache, value_cache = self.token_to_kv_pool.get_kv_buffer(layer.layer_id)
|
||||||
key_cache = key_cache.view(
|
key_cache = key_cache.view(
|
||||||
-1, self.page_size, layer.tp_k_head_num, layer.head_dim
|
-1, self.page_size, layer.tp_k_head_num, layer.head_dim
|
||||||
@@ -987,6 +1007,12 @@ class XPUAttentionBackend(AttentionBackend):
|
|||||||
metadata.page_table,
|
metadata.page_table,
|
||||||
self.workspace,
|
self.workspace,
|
||||||
layer.scaling,
|
layer.scaling,
|
||||||
|
# flash_mla_decode's heuristic only kicks in when num_kv_splits
|
||||||
|
# < 1, and it derives the split count from batch * num_heads and
|
||||||
|
# seq_len_kv, which is not batch-invariant. Pin it to 1 (the
|
||||||
|
# kernel's current default) so the reduction order stays fixed
|
||||||
|
# regardless of upstream default changes.
|
||||||
|
num_kv_splits=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
out = o.view(-1, layer.tp_q_head_num * layer.v_head_dim)
|
out = o.view(-1, layer.tp_q_head_num * layer.v_head_dim)
|
||||||
|
|||||||
@@ -241,6 +241,7 @@ DETERMINISTIC_ATTENTION_BACKEND_CHOICES = [
|
|||||||
"fa3",
|
"fa3",
|
||||||
"fa4",
|
"fa4",
|
||||||
"flashinfer",
|
"flashinfer",
|
||||||
|
"intel_xpu",
|
||||||
"triton",
|
"triton",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -9,17 +9,29 @@ test into unit tests so that's easily reproducible in CI.
|
|||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from sglang.test.ci.ci_register import register_amd_ci, register_cuda_ci
|
from sglang.srt.utils import is_xpu
|
||||||
|
from sglang.test.ci.ci_register import (
|
||||||
|
register_amd_ci,
|
||||||
|
register_cuda_ci,
|
||||||
|
register_xpu_ci,
|
||||||
|
)
|
||||||
from sglang.test.test_deterministic_utils import (
|
from sglang.test.test_deterministic_utils import (
|
||||||
COMMON_SERVER_ARGS,
|
COMMON_SERVER_ARGS,
|
||||||
TestDeterministicBase,
|
TestDeterministicBase,
|
||||||
)
|
)
|
||||||
from sglang.test.test_utils import is_in_amd_ci
|
from sglang.test.test_utils import (
|
||||||
|
DEFAULT_SMALL_MODEL_NAME_FOR_TEST_QWEN,
|
||||||
|
is_in_amd_ci,
|
||||||
|
)
|
||||||
|
|
||||||
register_cuda_ci(est_time=207, stage="base-b", runner_config="1-gpu-large")
|
register_cuda_ci(est_time=207, stage="base-b", runner_config="1-gpu-large")
|
||||||
register_amd_ci(est_time=278, suite="stage-b-test-1-gpu-small-amd")
|
register_amd_ci(est_time=278, suite="stage-b-test-1-gpu-small-amd")
|
||||||
|
register_xpu_ci(est_time=207, suite="stage-b-test-1-gpu-xpu")
|
||||||
|
|
||||||
|
_is_xpu = is_xpu()
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(_is_xpu, "CUDA runner only")
|
||||||
@unittest.skipIf(is_in_amd_ci(), "Skip for AMD CI.")
|
@unittest.skipIf(is_in_amd_ci(), "Skip for AMD CI.")
|
||||||
class TestFlashinferDeterministic(TestDeterministicBase):
|
class TestFlashinferDeterministic(TestDeterministicBase):
|
||||||
# Test with flashinfer attention backend
|
# Test with flashinfer attention backend
|
||||||
@@ -35,6 +47,7 @@ class TestFlashinferDeterministic(TestDeterministicBase):
|
|||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(_is_xpu, "CUDA runner only")
|
||||||
@unittest.skipIf(is_in_amd_ci(), "Skip for AMD CI.")
|
@unittest.skipIf(is_in_amd_ci(), "Skip for AMD CI.")
|
||||||
class TestFa3Deterministic(TestDeterministicBase):
|
class TestFa3Deterministic(TestDeterministicBase):
|
||||||
# Test with fa3 attention backend
|
# Test with fa3 attention backend
|
||||||
@@ -50,6 +63,7 @@ class TestFa3Deterministic(TestDeterministicBase):
|
|||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(_is_xpu, "CUDA/AMD runner only")
|
||||||
class TestTritonDeterministic(TestDeterministicBase):
|
class TestTritonDeterministic(TestDeterministicBase):
|
||||||
# Test with triton attention backend
|
# Test with triton attention backend
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -64,5 +78,29 @@ class TestTritonDeterministic(TestDeterministicBase):
|
|||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipUnless(_is_xpu, "XPU runner only")
|
||||||
|
class TestIntelXPUDeterministic(TestDeterministicBase):
|
||||||
|
# Test with intel_xpu attention backend using smaller model to avoid OOM
|
||||||
|
@classmethod
|
||||||
|
def get_model(cls):
|
||||||
|
# Use smaller model for XPU to avoid OOM
|
||||||
|
return DEFAULT_SMALL_MODEL_NAME_FOR_TEST_QWEN
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_server_args(cls):
|
||||||
|
args = COMMON_SERVER_ARGS
|
||||||
|
args.extend(
|
||||||
|
[
|
||||||
|
"--attention-backend",
|
||||||
|
"intel_xpu",
|
||||||
|
"--device",
|
||||||
|
"xpu",
|
||||||
|
"--mem-fraction-static",
|
||||||
|
"0.80",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user