chore: vendor sglang v0.5.10 snapshot
This commit is contained in:
184
third_party/sglang/sgl-kernel/tests/test_moe_topk_softmax.py
vendored
Normal file
184
third_party/sglang/sgl-kernel/tests/test_moe_topk_softmax.py
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
import itertools
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
import torch
|
||||
from sgl_kernel import topk_softmax
|
||||
|
||||
|
||||
def compare_topk_values(gating_output, topk_indices_ref, topk_indices):
|
||||
values_ref = torch.gather(gating_output, 1, topk_indices_ref)
|
||||
values = torch.gather(gating_output, 1, topk_indices)
|
||||
return torch.equal(values_ref, values)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"num_tokens, num_experts, topk",
|
||||
list(
|
||||
itertools.product(
|
||||
[1, 16, 128, 512, 1024, 2048], # num_tokens
|
||||
[512], # num_experts
|
||||
[1, 2, 3, 4, 5, 8], # topk
|
||||
)
|
||||
),
|
||||
)
|
||||
def test_topkfast_softmax(num_tokens, num_experts, topk):
|
||||
gating_output = torch.randn(
|
||||
(num_tokens, num_experts), dtype=torch.float32, device="cuda"
|
||||
)
|
||||
|
||||
topk_weights = torch.empty((num_tokens, topk), dtype=torch.float32, device="cuda")
|
||||
topk_indices = torch.empty((num_tokens, topk), dtype=torch.int32, device="cuda")
|
||||
|
||||
topk_softmax(
|
||||
topk_weights,
|
||||
topk_indices,
|
||||
gating_output,
|
||||
)
|
||||
|
||||
# Native torch implementation
|
||||
softmax_output = torch.softmax(gating_output, dim=-1)
|
||||
topk_weights_ref, topk_indices_ref = torch.topk(softmax_output, topk, dim=-1)
|
||||
|
||||
# Verify the top-k weights and indices match the torch native ones
|
||||
assert torch.allclose(
|
||||
topk_weights_ref, topk_weights, atol=1e-3, rtol=1e-3
|
||||
), f"Weights mismatch: torch={topk_indices_ref} vs SGLang={topk_weights}"
|
||||
|
||||
assert compare_topk_values(
|
||||
gating_output, topk_indices_ref.int(), topk_indices
|
||||
), f"Values at the two indices are not equal: torch={topk_indices_ref}, SGLang={topk_indices}, values={gating_output}"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"num_tokens, num_experts, topk",
|
||||
list(
|
||||
itertools.product(
|
||||
[1, 16, 128, 512, 1024, 2048], # num_tokens
|
||||
[4, 8, 16, 32, 64, 128, 256], # num_experts
|
||||
[1, 2, 4], # topk
|
||||
)
|
||||
),
|
||||
)
|
||||
def test_topk_softmax(num_tokens, num_experts, topk):
|
||||
gating_output = torch.randn(
|
||||
(num_tokens, num_experts), dtype=torch.float32, device="cuda"
|
||||
)
|
||||
|
||||
topk_weights = torch.empty((num_tokens, topk), dtype=torch.float32, device="cuda")
|
||||
topk_indices = torch.empty((num_tokens, topk), dtype=torch.int32, device="cuda")
|
||||
|
||||
topk_softmax(
|
||||
topk_weights,
|
||||
topk_indices,
|
||||
gating_output,
|
||||
)
|
||||
|
||||
# Native torch implementation
|
||||
softmax_output = torch.softmax(gating_output, dim=-1)
|
||||
topk_weights_ref, topk_indices_ref = torch.topk(softmax_output, topk, dim=-1)
|
||||
|
||||
# Verify the top-k weights and indices match the torch native ones
|
||||
assert torch.allclose(
|
||||
topk_weights_ref, topk_weights, atol=1e-3, rtol=1e-3
|
||||
), f"Weights mismatch: torch={topk_indices_ref} vs SGLang={topk_weights}"
|
||||
|
||||
assert compare_topk_values(
|
||||
gating_output, topk_indices_ref.int(), topk_indices
|
||||
), f"Values at the two indices are not equal: torch={topk_indices_ref}, SGLang={topk_indices}, values={gating_output}"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"num_tokens, num_experts, topk, dtype",
|
||||
list(
|
||||
itertools.product(
|
||||
[1, 16, 128, 512, 1024, 2048], # num_tokens
|
||||
[4, 8, 16, 32, 64, 128, 256, 512], # num_experts
|
||||
[1, 2, 4], # topk
|
||||
[torch.float16, torch.bfloat16, torch.float32], # dtype
|
||||
)
|
||||
),
|
||||
)
|
||||
def test_topk_softmax_dtype_regression(num_tokens, num_experts, topk, dtype):
|
||||
gating_output = torch.randn((num_tokens, num_experts), dtype=dtype, device="cuda")
|
||||
|
||||
topk_weights = torch.empty((num_tokens, topk), dtype=torch.float32, device="cuda")
|
||||
topk_indices = torch.empty((num_tokens, topk), dtype=torch.int32, device="cuda")
|
||||
|
||||
topk_softmax(
|
||||
topk_weights,
|
||||
topk_indices,
|
||||
gating_output,
|
||||
)
|
||||
|
||||
topk_weights_ref = torch.empty(
|
||||
(num_tokens, topk), dtype=torch.float32, device="cuda"
|
||||
)
|
||||
topk_indices_ref = torch.empty((num_tokens, topk), dtype=torch.int32, device="cuda")
|
||||
|
||||
topk_softmax(
|
||||
topk_weights_ref,
|
||||
topk_indices_ref,
|
||||
gating_output.float(),
|
||||
)
|
||||
|
||||
assert torch.allclose(
|
||||
topk_weights_ref, topk_weights, atol=1e-3, rtol=1e-3
|
||||
), f"Weights mismatch: SGLang old interface={topk_indices_ref} vs SGLang new interface={topk_weights}"
|
||||
|
||||
assert compare_topk_values(
|
||||
gating_output, topk_indices_ref.int(), topk_indices
|
||||
), f"Values at the two indices are not equal: torch={topk_indices_ref}, SGLang={topk_indices}, values={gating_output}"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"num_tokens, num_experts, topk",
|
||||
list(
|
||||
itertools.product(
|
||||
[1, 16, 128, 512, 1024, 2048], # num_tokens
|
||||
[4, 8, 16, 32, 64, 128, 256, 512], # num_experts
|
||||
[1, 2, 4], # topk
|
||||
)
|
||||
),
|
||||
)
|
||||
def test_topk_softmax_renormalize(num_tokens, num_experts, topk):
|
||||
gating_output = torch.randn(
|
||||
(num_tokens, num_experts), dtype=torch.bfloat16, device="cuda"
|
||||
)
|
||||
|
||||
topk_weights = torch.empty((num_tokens, topk), dtype=torch.float32, device="cuda")
|
||||
topk_indices = torch.empty((num_tokens, topk), dtype=torch.int32, device="cuda")
|
||||
|
||||
topk_softmax(
|
||||
topk_weights,
|
||||
topk_indices,
|
||||
gating_output,
|
||||
renormalize=True,
|
||||
)
|
||||
|
||||
topk_weights_ref = torch.empty(
|
||||
(num_tokens, topk), dtype=torch.float32, device="cuda"
|
||||
)
|
||||
topk_indices_ref = torch.empty((num_tokens, topk), dtype=torch.int32, device="cuda")
|
||||
token_expert_indices_ref = torch.empty(
|
||||
(num_tokens, topk), dtype=torch.int32, device="cuda"
|
||||
)
|
||||
|
||||
topk_softmax(
|
||||
topk_weights_ref,
|
||||
topk_indices_ref,
|
||||
gating_output,
|
||||
)
|
||||
topk_weights_ref = topk_weights_ref / topk_weights_ref.sum(dim=-1, keepdim=True)
|
||||
|
||||
assert torch.allclose(
|
||||
topk_weights_ref, topk_weights, atol=1e-3, rtol=1e-3
|
||||
), f"Weights mismatch: SGLang w/o fused renormalize={topk_indices_ref} vs SGLang w/ fused renormalize={topk_weights}"
|
||||
|
||||
assert compare_topk_values(
|
||||
gating_output, topk_indices_ref.int(), topk_indices
|
||||
), f"Values at the two indices are not equal: torch={topk_indices_ref}, SGLang={topk_indices}, values={gating_output}"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(pytest.main([__file__]))
|
||||
Reference in New Issue
Block a user