Add stochastic rounding for FP16 Mamba SSM cache (#26929)
Signed-off-by: Daniel Afrimi <dafrimi@login-lyris01.lyris.clusters.nvidia.com> Co-authored-by: Daniel Afrimi <dafrimi@login-lyris01.lyris.clusters.nvidia.com>
This commit is contained in:
co-authored by
Daniel Afrimi
parent
d5133e925b
commit
a2b5ce2ed1
@@ -14,8 +14,8 @@ import torch.nn.functional as F
|
||||
from einops import rearrange, repeat
|
||||
|
||||
from sglang.srt.layers.attention.mamba.causal_conv1d_triton import PAD_SLOT_ID
|
||||
from sglang.srt.layers.attention.mamba.ops import selective_state_update
|
||||
from sglang.srt.utils import get_device
|
||||
from sglang.srt.layers.attention.mamba.ops.mamba_ssm import selective_state_update
|
||||
from sglang.srt.utils import get_device, is_sm100_supported
|
||||
|
||||
|
||||
def selective_state_update_ref(
|
||||
@@ -297,6 +297,67 @@ def test_selective_state_update_with_heads_with_batch_indices(
|
||||
assert torch.allclose(out, out_ref, rtol=rtol, atol=atol)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not is_sm100_supported(),
|
||||
reason=(
|
||||
"Triton stochastic rounding uses cvt.rs.f16x2.f32 and requires "
|
||||
"SM100-family Blackwell with CUDA >= 12.8"
|
||||
),
|
||||
)
|
||||
@pytest.mark.parametrize("philox_rounds", [0, 4])
|
||||
@pytest.mark.parametrize("has_z", [False, True])
|
||||
@pytest.mark.parametrize("dstate", [16, 64])
|
||||
@pytest.mark.parametrize("dim", [2048, 4096])
|
||||
def test_selective_state_update_stochastic_rounding(dim, dstate, has_z, philox_rounds):
|
||||
device = "cuda"
|
||||
torch.manual_seed(0)
|
||||
|
||||
batch_size = 2
|
||||
state = torch.randn(batch_size, dim, dstate, dtype=torch.float16, device=device)
|
||||
x = torch.randn(batch_size, dim, device=device, dtype=torch.bfloat16)
|
||||
out = torch.empty_like(x)
|
||||
dt = torch.randn(batch_size, dim, device=device, dtype=torch.bfloat16)
|
||||
dt_bias = torch.rand(dim, device=device) - 4.0
|
||||
A = -torch.rand(dim, dstate, device=device) - 1.0
|
||||
B = torch.randn(batch_size, dstate, device=device)
|
||||
C = torch.randn(batch_size, dstate, device=device)
|
||||
D = torch.randn(dim, device=device)
|
||||
z = torch.randn_like(x) if has_z else None
|
||||
state_ref = state.float()
|
||||
|
||||
selective_state_update(
|
||||
state,
|
||||
x,
|
||||
dt,
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
D=D,
|
||||
z=z,
|
||||
dt_bias=dt_bias,
|
||||
dt_softplus=True,
|
||||
out=out,
|
||||
enable_stochastic_rounding=True,
|
||||
cache_philox_rounds=philox_rounds,
|
||||
)
|
||||
out_ref = selective_state_update_ref(
|
||||
state_ref,
|
||||
x,
|
||||
dt,
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
D=D,
|
||||
z=z,
|
||||
dt_bias=dt_bias,
|
||||
dt_softplus=True,
|
||||
)
|
||||
|
||||
assert state.dtype == torch.float16
|
||||
assert torch.allclose(state, state_ref.to(torch.float16), rtol=5e-3, atol=1e-1)
|
||||
assert torch.allclose(out, out_ref, rtol=5e-3, atol=1e-1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
|
||||
@@ -71,6 +71,42 @@ class TestPrepareServerArgs(CustomTestCase):
|
||||
os.unlink(config_file)
|
||||
|
||||
|
||||
class TestMambaCacheStochasticRounding(unittest.TestCase):
|
||||
def test_rejects_fp32_ssm_cache(self):
|
||||
server_args = ServerArgs(
|
||||
model_path="dummy",
|
||||
mamba_ssm_dtype="float32",
|
||||
enable_mamba_cache_stochastic_rounding=True,
|
||||
)
|
||||
|
||||
with self.assertRaisesRegex(ValueError, "--mamba-ssm-dtype float16"):
|
||||
server_args._handle_mamba_backend()
|
||||
|
||||
@patch("sglang.srt.server_args.is_cuda", return_value=False)
|
||||
def test_rejects_non_cuda(self, _mock_is_cuda):
|
||||
server_args = ServerArgs(
|
||||
model_path="dummy",
|
||||
mamba_ssm_dtype="float16",
|
||||
enable_mamba_cache_stochastic_rounding=True,
|
||||
)
|
||||
|
||||
with self.assertRaisesRegex(ValueError, "NVIDIA CUDA"):
|
||||
server_args._handle_mamba_backend()
|
||||
|
||||
@patch("sglang.srt.server_args.is_cuda", return_value=True)
|
||||
@patch("sglang.srt.server_args.is_sm100_supported", return_value=False)
|
||||
def test_rejects_triton_without_sm100(self, _mock_sm100, _mock_is_cuda):
|
||||
server_args = ServerArgs(
|
||||
model_path="dummy",
|
||||
mamba_ssm_dtype="float16",
|
||||
mamba_backend="triton",
|
||||
enable_mamba_cache_stochastic_rounding=True,
|
||||
)
|
||||
|
||||
with self.assertRaisesRegex(ValueError, "requires SM100"):
|
||||
server_args._handle_mamba_backend()
|
||||
|
||||
|
||||
class TestLoadBalanceMethod(unittest.TestCase):
|
||||
def test_non_pd_defaults_to_round_robin(self):
|
||||
server_args = ServerArgs(model_path="dummy", disaggregation_mode="null")
|
||||
|
||||
Reference in New Issue
Block a user