main
py 209 lines 6.72 KB
Raw
1 #!/usr/bin/env python3
2 # SPDX-License-Identifier: Apache-2.0
3 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
4 """Test script for the token-to-expert routing simulator.
5
6 This script demonstrates how to use the routing simulator to test
7 different routing strategies and analyze their performance, including
8 integration tests with FusedMoEFactory layer.
9 """
10
11 import tempfile
12
13 import pytest
14 import torch
15
16 from vllm.config import VllmConfig, set_current_vllm_config
17 from vllm.distributed import (
18 init_distributed_environment,
19 initialize_model_parallel,
20 )
21 from vllm.model_executor.layers.fused_moe.router.routing_simulator_router import (
22 DistributionBasedRouting,
23 RoutingSimulator,
24 )
25
26
27 @pytest.fixture
28 def device():
29 """Fixture to provide the appropriate device for testing."""
30 return torch.device("cuda" if torch.cuda.is_available() else "cpu")
31
32
33 @pytest.mark.parametrize("num_tokens", [1, 16, 256])
34 @pytest.mark.parametrize("hidden_size", [64, 1024])
35 @pytest.mark.parametrize("num_experts", [16, 128])
36 @pytest.mark.parametrize("top_k", [1, 4])
37 def test_basic_functionality(
38 num_tokens: int,
39 hidden_size: int,
40 num_experts: int,
41 top_k: int,
42 device,
43 ):
44 """Test basic functionality of the routing simulator."""
45 # Test each routing strategy
46 strategies = RoutingSimulator.get_available_strategies()
47
48 hidden_states = torch.randn(num_tokens, hidden_size, device=device)
49 router_logits = torch.randn(num_tokens, num_experts, device=device)
50
51 for strategy in strategies:
52 # Simulate routing
53 topk_weights, topk_ids = RoutingSimulator.simulate_routing(
54 hidden_states=hidden_states,
55 router_logits=router_logits,
56 strategy_name=strategy,
57 top_k=top_k,
58 )
59
60 # Check output shapes
61 assert topk_weights.shape == (
62 num_tokens,
63 top_k,
64 ), f"Wrong weights shape for {strategy}"
65 assert topk_ids.shape == (
66 num_tokens,
67 top_k,
68 ), f"Wrong ids shape for {strategy}"
69
70 # Check that expert IDs are valid
71 assert topk_ids.min() >= 0, f"Invalid expert ID (negative) for {strategy}"
72 assert topk_ids.max() < num_experts, (
73 f"Invalid expert ID (too large) for {strategy}"
74 )
75
76
77 def test_routing_strategy_integration(monkeypatch, device):
78 """Test that the routing strategy environment variable works with
79 FusedMoEFactory."""
80 pytest.importorskip("vllm.model_executor.layers.fused_moe.layer")
81
82 import vllm.envs as envs
83 from vllm.model_executor.layers.fused_moe.layer import FusedMoEFactory
84
85 # Test parameters
86 num_tokens = 32
87 hidden_size = 16
88 num_experts = 4
89 top_k = 2
90
91 # Create test data
92 hidden_states = torch.randn(num_tokens, hidden_size, device=device)
93 router_logits = torch.randn(num_tokens, num_experts, device=device)
94
95 # Test different routing strategies
96 strategies = RoutingSimulator.get_available_strategies()
97
98 vllm_config = VllmConfig()
99 with set_current_vllm_config(vllm_config):
100 temp_file = tempfile.mkstemp()[1]
101 init_distributed_environment(
102 world_size=1,
103 rank=0,
104 local_rank=0,
105 distributed_init_method=f"file://{temp_file}",
106 )
107 initialize_model_parallel(
108 tensor_model_parallel_size=1,
109 pipeline_model_parallel_size=1,
110 )
111
112 for strategy in strategies:
113 fused_moe = FusedMoEFactory(
114 num_experts=num_experts,
115 top_k=top_k,
116 hidden_size=hidden_size,
117 intermediate_size=0,
118 use_grouped_topk=False,
119 renormalize=True,
120 prefix=strategy,
121 )
122
123 # Set environment variable
124 env_name = "VLLM_MOE_ROUTING_SIMULATION_STRATEGY"
125 monkeypatch.setenv(env_name, strategy)
126
127 # Temporarily override the envs lookup so the router factory
128 # reads the monkeypatched value instead of the module-load-time
129 # default. Use monkeypatch.setitem so the original lambda is
130 # restored automatically at teardown.
131 monkeypatch.setitem(
132 envs.environment_variables,
133 env_name,
134 lambda s=strategy: s,
135 )
136
137 # Test the select_experts method
138 topk_weights, topk_ids = fused_moe.router.select_experts(
139 hidden_states=hidden_states,
140 router_logits=router_logits,
141 )
142
143 # Verify output shapes
144 assert topk_weights.shape == (num_tokens, top_k), (
145 f"Wrong weights shape for {strategy}"
146 )
147 assert topk_ids.shape == (num_tokens, top_k), (
148 f"Wrong ids shape for {strategy}"
149 )
150
151 # Verify expert IDs are valid
152 assert topk_ids.min() >= 0, f"Invalid expert ID (negative) for {strategy}"
153 assert topk_ids.max() < num_experts, (
154 f"Invalid expert ID (too large) for {strategy}"
155 )
156
157
158 def test_distribution_based_routing_with_custom_strategy():
159 """Test registering and using DistributionBasedRouting with custom
160 parameters."""
161 device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
162
163 # Register custom distribution-based strategy
164 custom_strategy = DistributionBasedRouting(distribution="normal", mean=2.0, std=0.5)
165 RoutingSimulator.register_strategy("custom_normal", custom_strategy)
166
167 # Test data
168 num_tokens = 60
169 hidden_size = 48
170 num_experts = 6
171 top_k = 3
172
173 hidden_states = torch.randn(num_tokens, hidden_size, device=device)
174 router_logits = torch.randn(num_tokens, num_experts, device=device)
175
176 # Use the custom strategy
177 topk_weights, topk_ids = RoutingSimulator.simulate_routing(
178 hidden_states=hidden_states,
179 router_logits=router_logits,
180 strategy_name="custom_normal",
181 top_k=top_k,
182 )
183
184 # Check output shapes
185 assert topk_weights.shape == (num_tokens, top_k)
186 assert topk_ids.shape == (num_tokens, top_k)
187
188 # Check that expert IDs are valid
189 assert topk_ids.min() >= 0
190 assert topk_ids.max() < num_experts
191
192
193 def test_instance_compatibility():
194 """Test that static methods work correctly."""
195 device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
196
197 # Test static method directly
198 hidden_states = torch.randn(10, 8, device=device)
199 router_logits = torch.randn(10, 4, device=device)
200
201 topk_weights, topk_ids = RoutingSimulator.simulate_routing(
202 hidden_states=hidden_states,
203 router_logits=router_logits,
204 strategy_name="uniform_random",
205 top_k=2,
206 )
207
208 assert topk_weights.shape == (10, 2)
209 assert topk_ids.shape == (10, 2)