@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 72c62eae5f
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 15, 21:00 UTC

[V1] EP/TP MoE + DP Attention (#13931)

Tyler Michael Smith committed Mar 5, 2025 at 00:27 UTC 72c62eae5f010e45e027f51593d68798f84ee789
17 files changed +250 -75
examples/offline_inference/data_parallel.py
+10 -7
@@ -1,5 +1,7 @@
1 # SPDX-License-Identifier: Apache-2.0
2 -# usage: VLLM_USE_V1=1 python examples/offline_inference/data_parallel.py
2 +# usage:
3 +# VLLM_TEST_ENABLE_EP=1 VLLM_USE_V1=1 \
4 +# python examples/offline_inference/data_parallel.py
5 # we need to have a launcher to create multiple data parallel
6 # ranks. And each rank will create a vLLM instance to process its own prompts.
7 import os
@@ -7,6 +9,9 @@ import os
9 from vllm import LLM, SamplingParams
10 from vllm.utils import get_open_port
11
12 +GPUs_per_dp_rank = 2
13 +DP_size = 2
14 +
15
16 def main(dp_size, dp_rank, dp_master_ip, dp_master_port, GPUs_per_dp_rank):
17 os.environ["VLLM_DP_RANK"] = str(dp_rank)
@@ -48,8 +53,8 @@ def main(dp_size, dp_rank, dp_master_ip, dp_master_port, GPUs_per_dp_rank):
53 max_tokens=16 * (dp_rank + 1))
54
55 # Create an LLM.
51 - llm = LLM(model="facebook/opt-125m",
52 - tensor_parallel_size=2,
56 + llm = LLM(model="ibm-research/PowerMoE-3b",
57 + tensor_parallel_size=GPUs_per_dp_rank,
58 enforce_eager=True)
59 outputs = llm.generate(prompts, sampling_params)
60 # Print the outputs.
@@ -62,14 +67,12 @@ def main(dp_size, dp_rank, dp_master_ip, dp_master_port, GPUs_per_dp_rank):
67
68 if __name__ == "__main__":
69 from multiprocessing import Process
65 - dp_size = 2
66 - GPUs_per_dp_rank = 2
70 dp_master_ip = "127.0.0.1"
71 dp_master_port = get_open_port()
72 procs = []
70 - for i in range(dp_size):
73 + for i in range(DP_size):
74 proc = Process(target=main,
72 - args=(dp_size, i, dp_master_ip, dp_master_port,
75 + args=(DP_size, i, dp_master_ip, dp_master_port,
76 GPUs_per_dp_rank))
77 proc.start()
78 procs.append(proc)
tests/kernels/test_moe.py
+1
@@ -217,6 +217,7 @@ def test_mixtral_moe(dtype: torch.dtype):
217 intermediate_size=config.intermediate_size,
218 params_dtype=dtype,
219 tp_size=1,
220 + dp_size=1,
221 ).cuda()
222
223 # Load the weights
vllm/attention/layer.py
+2 -2
@@ -324,7 +324,7 @@ def unified_attention(
324 ) -> torch.Tensor:
325 forward_context: ForwardContext = get_forward_context()
326 attn_metadata = forward_context.attn_metadata
327 - self = forward_context.attn_layers[layer_name]
327 + self = forward_context.no_compile_layers[layer_name]
328 kv_cache = self.kv_cache[forward_context.virtual_engine]
329 return self.impl.forward(self, query, key, value, kv_cache, attn_metadata)
330
@@ -356,7 +356,7 @@ def unified_attention_with_output(
356 ) -> None:
357 forward_context: ForwardContext = get_forward_context()
358 attn_metadata = forward_context.attn_metadata
359 - self = forward_context.attn_layers[layer_name]
359 + self = forward_context.no_compile_layers[layer_name]
360 kv_cache = self.kv_cache[forward_context.virtual_engine]
361 self.impl.forward(self,
362 query,
vllm/compilation/backends.py
+3 -2
@@ -396,8 +396,9 @@ class VllmBackend:
396
397 cache_dir = self.compilation_config.cache_dir
398 os.makedirs(cache_dir, exist_ok=True)
399 - local_cache_dir = os.path.join(
400 - cache_dir, f"rank_{vllm_config.parallel_config.rank}")
399 + rank = vllm_config.parallel_config.rank
400 + dp_rank = vllm_config.parallel_config.data_parallel_rank
401 + local_cache_dir = os.path.join(cache_dir, f"rank_{rank}_{dp_rank}")
402 self.compilation_config.local_cache_dir = local_cache_dir
403
404 disable_cache = envs.VLLM_DISABLE_COMPILE_CACHE
vllm/forward_context.py
+15 -7
@@ -25,16 +25,22 @@ batchsize_logging_interval: float = envs.VLLM_LOG_BATCHSIZE_INTERVAL
25 batchsize_forward_time: defaultdict = defaultdict(list)
26
27
28 +@dataclass
29 +class DPMetadata:
30 + num_tokens_across_dp: list[int]
31 + cu_tokens_across_dp_cpu: torch.Tensor
32 +
33 +
34 @dataclass
35 class ForwardContext:
36 # copy from vllm_config.compilation_config.static_forward_context
31 - attn_layers: dict[str, Any]
37 + no_compile_layers: dict[str, Any]
38 # TODO: extend to support per-layer dynamic forward context
39 attn_metadata: "AttentionMetadata" # set dynamically for each forward pass
40 # TODO: remove after making all virtual_engines share the same kv cache
41 virtual_engine: int # set dynamically for each forward pass
36 - num_tokens_across_dp: Optional[
37 - list[int]] = None # set dynamically for each forward pass
42 + # set dynamically for each forward pass
43 + dp_metadata: Optional[DPMetadata] = None
44
45
46 _forward_context: Optional[ForwardContext] = None
@@ -61,7 +67,7 @@ def set_forward_context(attn_metadata: Any,
67 need_to_track_batchsize = track_batchsize and attn_metadata is not None
68 if need_to_track_batchsize:
69 forward_start_time = time.perf_counter()
64 - num_tokens_across_dp = None
70 + dp_metadata: Optional[DPMetadata] = None
71 if vllm_config.parallel_config.data_parallel_size > 1:
72 dp_size = vllm_config.parallel_config.data_parallel_size
73 dp_rank = vllm_config.parallel_config.data_parallel_rank
@@ -82,15 +88,17 @@ def set_forward_context(attn_metadata: Any,
88 dtype=torch.int32)
89 from vllm.distributed.parallel_state import get_dp_group
90 dist.all_reduce(num_tokens_tensor, group=get_dp_group().cpu_group)
85 - num_tokens_across_dp = num_tokens_tensor.tolist()
91 + cu_tokens_across_dp_cpu = torch.cumsum(num_tokens_tensor, dim=0)
92 + dp_metadata = DPMetadata(num_tokens_across_dp, cu_tokens_across_dp_cpu)
93
94 global _forward_context
95 prev_context = _forward_context
96 _forward_context = ForwardContext(
90 - attn_layers=vllm_config.compilation_config.static_forward_context,
97 + no_compile_layers=vllm_config.compilation_config.
98 + static_forward_context,
99 virtual_engine=virtual_engine,
100 attn_metadata=attn_metadata,
93 - num_tokens_across_dp=num_tokens_across_dp)
101 + dp_metadata=dp_metadata)
102 try:
103 yield
104 finally:
vllm/model_executor/layers/fused_moe/layer.py
+155 -32
@@ -8,9 +8,11 @@ import torch
8 from torch.nn.parameter import UninitializedParameter
9
10 import vllm.envs as envs
11 -from vllm.distributed import (get_tensor_model_parallel_rank,
11 +from vllm.config import get_current_vllm_config
12 +from vllm.distributed import (get_dp_group, get_tensor_model_parallel_rank,
13 get_tensor_model_parallel_world_size,
14 tensor_model_parallel_all_reduce)
15 +from vllm.forward_context import ForwardContext, get_forward_context
16 from vllm.logger import init_logger
17 from vllm.model_executor.custom_op import CustomOp
18 from vllm.model_executor.layers.quantization.base_config import (
@@ -18,6 +20,7 @@ from vllm.model_executor.layers.quantization.base_config import (
20 from vllm.model_executor.utils import set_weight_attrs
21 from vllm.platforms import current_platform
22 from vllm.platforms.interface import CpuArchEnum
23 +from vllm.utils import direct_register_custom_op
24
25 if current_platform.is_cuda_alike():
26 from .fused_moe import fused_experts
@@ -246,6 +249,51 @@ class UnquantizedFusedMoEMethod(FusedMoEMethodBase, CustomOp):
249 forward_native = forward_cuda
250
251
252 +def determine_expert_map(
253 + ep_size: int, ep_rank: int,
254 + global_num_experts: int) -> Tuple[int, Optional[torch.Tensor]]:
255 + """
256 + Calculates how many experts should be assigned to each rank for EP and
257 + creates a mapping from global to local expert index. Experts are
258 + distributed evenly across ranks. Any remaining are assigned to the
259 + last rank.
260 +
261 + Args:
262 + ep_size (int): The size of the expert parallel group
263 + global_num_experts (int): The total number of experts in the model.
264 +
265 + Returns:
266 + Tuple[int, Optional[torch.Tensor]]: A tuple containing:
267 + - local_num_experts (int): The number of experts assigned
268 + to the current rank.
269 + - expert_map (Optional[torch.Tensor]): A tensor of shape
270 + (global_num_experts,) mapping from global to local index.
271 + Contains -1 for experts not assigned to the current rank.
272 + Returns None if ep_size is 1.
273 + """
274 + assert ep_size > 0
275 + if ep_size == 1:
276 + return (global_num_experts, None)
277 +
278 + local_num_experts = global_num_experts // ep_size
279 +
280 + # Create a tensor of size num_experts filled with -1
281 + expert_map = torch.full((global_num_experts, ), -1, dtype=torch.int32)
282 + # Create a expert map for the local experts
283 + if ep_rank < (ep_size - 1):
284 + # Each non-last rank gets local_num_experts experts.
285 + expert_map[ep_rank * local_num_experts:
286 + (ep_rank + 1) * local_num_experts] = \
287 + torch.arange(0, local_num_experts, dtype=torch.int32)
288 + else:
289 + # All remaining experts are assigned to the last rank.
290 + local_num_experts = (global_num_experts - ep_rank * local_num_experts)
291 +
292 + expert_map[-local_num_experts:] = \
293 + torch.arange(0, local_num_experts, dtype=torch.int32)
294 + return (local_num_experts, expert_map)
295 +
296 +
297 class FusedMoE(torch.nn.Module):
298 """FusedMoE layer for MoE models.
299
@@ -282,6 +330,7 @@ class FusedMoE(torch.nn.Module):
330 quant_config: Optional[QuantizationConfig] = None,
331 tp_size: Optional[int] = None,
332 ep_size: Optional[int] = None,
333 + dp_size: Optional[int] = None,
334 prefix: str = "",
335 custom_routing_function: Optional[Callable] = None,
336 scoring_func: str = "softmax",
@@ -293,16 +342,48 @@ class FusedMoE(torch.nn.Module):
342 if params_dtype is None:
343 params_dtype = torch.get_default_dtype()
344
345 + # For smuggling this layer into the fused moe custom op
346 + compilation_config = get_current_vllm_config().compilation_config
347 + if prefix in compilation_config.static_forward_context:
348 + raise ValueError("Duplicate layer name: {}".format(prefix))
349 + compilation_config.static_forward_context[prefix] = self
350 + self.layer_name = prefix
351 + self.use_direct_call = not envs.VLLM_TEST_ENABLE_EP
352 +
353 + # Note: here we guard against accessing the TP and DP groups when
354 + # uninitialized (this happens when testing)
355 self.tp_size = (tp_size if tp_size is not None else
356 get_tensor_model_parallel_world_size())
357 + tp_rank = 0 if self.tp_size == 1 else get_tensor_model_parallel_rank()
358 + self.dp_size = (dp_size
359 + if dp_size is not None else get_dp_group().world_size)
360 + self.dp_rank = (0
361 + if self.dp_size == 1 else get_dp_group().rank_in_group)
362 + self.global_num_experts = num_experts
363 +
364 if envs.VLLM_TEST_ENABLE_EP:
299 - self.ep_size = self.tp_size
365 + # Set TP size to 1 to adjust for EP and adjust EP size and rank
366 + # for DP attention.
367 + self.ep_rank = tp_rank + self.tp_size * self.dp_rank
368 + self.tp_rank = 0
369 + self.ep_size = self.tp_size * self.dp_size
370 self.tp_size = 1
371 +
372 + self.local_num_experts, self.expert_map = determine_expert_map(
373 + ep_size=self.ep_size,
374 + ep_rank=self.ep_rank,
375 + global_num_experts=self.global_num_experts)
376 else:
377 + # Adjust TP size for DP attention
378 + self.tp_rank = tp_rank + self.tp_size * self.dp_rank
379 + self.ep_rank = 0
380 + self.tp_size = self.tp_size * self.dp_size
381 self.ep_size = 1
382 + self.local_num_experts = self.global_num_experts
383 + self.expert_map = None
384 self.top_k = top_k
385 self.global_num_experts = num_experts
305 - self.local_num_experts = self.global_num_experts // self.ep_size
386 +
387 assert intermediate_size % self.tp_size == 0
388 self.intermediate_size_per_partition = intermediate_size // self.tp_size
389 self.reduce_results = reduce_results
@@ -316,26 +397,6 @@ class FusedMoE(torch.nn.Module):
397 self.scoring_func = scoring_func
398 self.e_score_correction_bias = e_score_correction_bias
399 self.activation = activation
319 - self.expert_map = None
320 -
321 - if self.ep_size > 1:
322 - # Create a tensor of size num_experts filled with -1
323 - self.expert_map = torch.full((self.global_num_experts, ),
324 - -1,
325 - dtype=torch.int32)
326 - # Create a expert map for the local experts
327 - ep_rank = get_tensor_model_parallel_rank()
328 - if ep_rank < (self.ep_size - 1):
329 - # Each non-last rank gets local_num_experts experts.
330 - self.expert_map[ep_rank * self.local_num_experts:
331 - (ep_rank + 1) * self.local_num_experts] = \
332 - torch.arange(0, self.local_num_experts, dtype=torch.int32)
333 - else:
334 - # All remaining experts are assigned to the last rank.
335 - self.local_num_experts = (self.global_num_experts -
336 - ep_rank * self.local_num_experts)
337 - self.expert_map[-self.local_num_experts:] = \
338 - torch.arange(0, self.local_num_experts, dtype=torch.int32)
400
401 if self.scoring_func != "softmax" and not self.use_grouped_topk:
402 raise ValueError("Only softmax scoring function is supported for "
@@ -493,9 +554,6 @@ class FusedMoE(torch.nn.Module):
554 if expert_id == -1:
555 return
556
496 - # TP rank is set to 0 if EP is enabled
497 - tp_rank = 0 if self.ep_size > 1 else get_tensor_model_parallel_rank()
498 -
557 # compressed-tensors checkpoints with packed weights are stored flipped
558 # TODO (mgoin): check self.quant_method.quant_config.quant_format
559 # against known CompressionFormat enum values that have this quality
@@ -539,8 +597,7 @@ class FusedMoE(torch.nn.Module):
597 final_shape = list(loaded_weight.shape)
598 if shard_id in ["w1", "w3"]:
599 final_shape[1] *= 2
542 - final_shape[shard_dim] = final_shape[
543 - shard_dim] // get_tensor_model_parallel_world_size()
600 + final_shape[shard_dim] = final_shape[shard_dim] // self.tp_size
601 param.materialize(final_shape, dtype=loaded_weight.dtype)
602
603 expert_data = param.data if full_load else param.data[expert_id]
@@ -567,7 +624,7 @@ class FusedMoE(torch.nn.Module):
624 shard_id=shard_id,
625 loaded_weight=loaded_weight,
626 expert_data=expert_data,
570 - tp_rank=tp_rank)
627 + tp_rank=self.tp_rank)
628 return
629
630 # Case weight scales and zero_points
@@ -584,7 +641,7 @@ class FusedMoE(torch.nn.Module):
641 shard_dim=shard_dim,
642 loaded_weight=loaded_weight,
643 expert_data=expert_data,
587 - tp_rank=tp_rank)
644 + tp_rank=self.tp_rank)
645 elif quant_method in [
646 FusedMoeWeightScaleSupported.GROUP.value,
647 FusedMoeWeightScaleSupported.BLOCK.value,
@@ -594,7 +651,7 @@ class FusedMoE(torch.nn.Module):
651 shard_dim=shard_dim,
652 loaded_weight=loaded_weight,
653 expert_data=expert_data,
597 - tp_rank=tp_rank,
654 + tp_rank=self.tp_rank,
655 load_full_w2=getattr(param, "load_full_w2", False))
656 elif quant_method == FusedMoeWeightScaleSupported.TENSOR.value:
657 self._load_per_tensor_weight_scale(shard_id=shard_id,
@@ -621,7 +678,7 @@ class FusedMoE(torch.nn.Module):
678 shard_dim=shard_dim,
679 loaded_weight=loaded_weight,
680 expert_data=expert_data,
624 - tp_rank=tp_rank)
681 + tp_rank=self.tp_rank)
682 return
683
684 @staticmethod
@@ -665,10 +722,45 @@ class FusedMoE(torch.nn.Module):
722
723 return topk_weights, topk_ids
724
725 + def naive_multicast(self, x: torch.Tensor,
726 + cu_tokens_across_dp_cpu: torch.Tensor):
727 + assert (len(x.shape) == 2)
728 + buffer = torch.empty((cu_tokens_across_dp_cpu[-1], x.size(1)),
729 + device=x.device,
730 + dtype=x.dtype)
731 +
732 + start = 0 if self.dp_rank == 0 else cu_tokens_across_dp_cpu[
733 + self.dp_rank - 1]
734 + end = cu_tokens_across_dp_cpu[self.dp_rank]
735 + buffer[start:end, :].copy_(x)
736 + for idx in range(get_dp_group().world_size):
737 + start = 0 if idx == 0 else cu_tokens_across_dp_cpu[idx - 1]
738 + end = cu_tokens_across_dp_cpu[idx]
739 + get_dp_group().broadcast(buffer[start:end, :], idx)
740 +
741 + return buffer
742 +
743 def forward(self, hidden_states: torch.Tensor,
744 router_logits: torch.Tensor):
745 + if self.use_direct_call:
746 + return self.forward_impl(hidden_states, router_logits)
747 + else:
748 + return torch.ops.vllm.moe_forward(hidden_states, router_logits,
749 + self.layer_name)
750 +
751 + def forward_impl(self, hidden_states: torch.Tensor,
752 + router_logits: torch.Tensor):
753 assert self.quant_method is not None
754
755 + if self.dp_size > 1:
756 + cu_tokens_across_dp_cpu = get_forward_context(
757 + ).dp_metadata.cu_tokens_across_dp_cpu
758 +
759 + hidden_states = self.naive_multicast(hidden_states,
760 + cu_tokens_across_dp_cpu)
761 + router_logits = self.naive_multicast(router_logits,
762 + cu_tokens_across_dp_cpu)
763 +
764 # Matrix multiply.
765 final_hidden_states = self.quant_method.apply(
766 layer=self,
@@ -687,6 +779,14 @@ class FusedMoE(torch.nn.Module):
779 activation=self.activation,
780 )
781
782 + if self.dp_size > 1:
783 + start = 0 if self.dp_rank == 0 else cu_tokens_across_dp_cpu[
784 + self.dp_rank - 1]
785 + end = cu_tokens_across_dp_cpu[self.dp_rank]
786 +
787 + all_hidden_states = get_dp_group().all_reduce(final_hidden_states)
788 + final_hidden_states = all_hidden_states[start:end, :]
789 +
790 if self.reduce_results and (self.tp_size > 1 or self.ep_size > 1):
791 # Default set to False. (May have to add shared expert outputs.)
792 final_hidden_states = tensor_model_parallel_all_reduce(
@@ -757,3 +857,26 @@ class FusedMoE(torch.nn.Module):
857 s += f", scoring_func='{self.scoring_func}', activation='{self.activation}'" # noqa: E501
858
859 return s
860 +
861 +
862 +def moe_forward(hidden_states: torch.Tensor, router_logits: torch.Tensor,
863 + layer_name: str) -> torch.Tensor:
864 + forward_context: ForwardContext = get_forward_context()
865 + self = forward_context.no_compile_layers[layer_name]
866 + assert self.quant_method is not None
867 +
868 + return self.forward_impl(hidden_states, router_logits)
869 +
870 +
871 +def moe_forward_fake(hidden_states: torch.Tensor, router_logits: torch.Tensor,
872 + layer_name: str) -> torch.Tensor:
873 + return torch.empty_like(hidden_states)
874 +
875 +
876 +direct_register_custom_op(
877 + op_name="moe_forward",
878 + op_func=moe_forward,
879 + mutates_args=[],
880 + fake_impl=moe_forward_fake,
881 + dispatch_key=current_platform.dispatch_key,
882 +)
vllm/model_executor/models/aria.py
+11 -7
@@ -46,7 +46,7 @@ class AriaImagePixelInputs(TypedDict):
46 pixel_values: torch.Tensor
47 pixel_mask: Optional[torch.Tensor]
48 """
49 - Shape:
49 + Shape:
50 pixel_values: `(batch_size * num_images, num_channels, height, width)`
51 pixel_mask: `(batch_size * num_images, height, width)`
52 """
@@ -135,11 +135,11 @@ class AriaProjector(nn.Module):
135 query numbers,
136 e.g., {1225: 128, 4900: 256}. This allows for different query sizes
137 based on image resolution.
138 - embed_dim (int): Embedding dimension.
139 - num_heads (int): Number of attention heads.
140 - kv_dim (int): Dimension of key and value.
141 - ff_dim (int): Hidden dimension of the feed-forward network.
142 - output_dim (int): Output dimension.
138 + embed_dim (int): Embedding dimension.
139 + num_heads (int): Number of attention heads.
140 + kv_dim (int): Dimension of key and value.
141 + ff_dim (int): Hidden dimension of the feed-forward network.
142 + output_dim (int): Output dimension.
143 norm_layer (nn.Module): Normalization layer. Default is nn.LayerNorm.
144
145 Outputs:
@@ -239,6 +239,7 @@ class AriaTextMoELayer(nn.Module):
239 self,
240 config: AriaTextConfig,
241 quant_config: Optional[QuantizationConfig],
242 + prefix: str = "",
243 ) -> None:
244 super().__init__()
245 self.config = config
@@ -254,6 +255,7 @@ class AriaTextMoELayer(nn.Module):
255 intermediate_size=config.intermediate_size,
256 quant_config=quant_config,
257 reduce_results=True,
258 + prefix=f"{prefix}.experts",
259 )
260 self.shared_experts = LlamaMLP(
261 config.hidden_size,
@@ -301,7 +303,9 @@ class AriaTextDecoderLayer(LlamaDecoderLayer):
303 prefix: str = "",
304 ) -> None:
305 super().__init__(config, cache_config, quant_config, prefix)
304 - self.mlp = AriaTextMoELayer(config, quant_config=quant_config)
306 + self.mlp = AriaTextMoELayer(config,
307 + quant_config=quant_config,
308 + prefix=f"{prefix}.mlp")
309
310
311 class AriaTextModel(LlamaModel, SupportsQuant):
vllm/model_executor/models/dbrx.py
+6 -2
@@ -65,6 +65,7 @@ class DbrxExperts(FusedMoE):
65 config: DbrxConfig,
66 quant_config: Optional[QuantizationConfig] = None,
67 params_dtype: Optional[torch.dtype] = None,
68 + prefix: str = "",
69 ):
70 super().__init__(
71 num_experts=config.ffn_config.moe_num_experts,
@@ -76,6 +77,7 @@ class DbrxExperts(FusedMoE):
77 renormalize=True,
78 quant_config=quant_config,
79 tp_size=get_tensor_model_parallel_world_size(),
80 + prefix=prefix,
81 )
82 self.config = config
83 self.tp_size = get_tensor_model_parallel_world_size()
@@ -139,6 +141,7 @@ class DbrxMoE(nn.Module):
141 config: DbrxConfig,
142 quant_config: Optional[QuantizationConfig] = None,
143 params_dtype: Optional[torch.dtype] = None,
144 + prefix: str = "",
145 ):
146 super().__init__()
147 self.d_model = config.d_model
@@ -150,7 +153,8 @@ class DbrxMoE(nn.Module):
153
154 self.experts = DbrxExperts(config=config,
155 quant_config=quant_config,
153 - params_dtype=self.params_dtype)
156 + params_dtype=self.params_dtype,
157 + prefix=f"{prefix}.experts")
158
159 def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
160 orig_shape = hidden_states.shape
@@ -291,7 +295,7 @@ class DbrxBlock(nn.Module):
295 cache_config,
296 quant_config,
297 prefix=f"{prefix}.norm_attn_norm")
294 - self.ffn = DbrxMoE(config, quant_config)
298 + self.ffn = DbrxMoE(config, quant_config, prefix=f"{prefix}.ffn")
299
300 def forward(
301 self,
vllm/model_executor/models/jamba.py
+15 -6
@@ -47,7 +47,8 @@ class JambaMoE(nn.Module):
47 top_k: Optional[int] = None,
48 params_dtype: Optional[torch.dtype] = None,
49 tp_size: Optional[int] = None,
50 - quant_config: Optional[QuantizationConfig] = None):
50 + quant_config: Optional[QuantizationConfig] = None,
51 + prefix: str = ""):
52 super().__init__()
53 self.num_total_experts = num_experts or config.num_experts
54 self.top_k = top_k or config.num_experts_per_tok
@@ -70,7 +71,8 @@ class JambaMoE(nn.Module):
71 reduce_results=True,
72 renormalize=False,
73 use_grouped_topk=False,
73 - quant_config=quant_config)
74 + quant_config=quant_config,
75 + prefix=f"{prefix}.experts")
76
77 def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
78 orig_shape = hidden_states.shape
@@ -92,13 +94,15 @@ class JambaMLP(JambaMoE):
94 config: JambaConfig,
95 params_dtype: Optional[torch.dtype] = None,
96 tp_size: Optional[int] = None,
95 - quant_config: Optional[QuantizationConfig] = None):
97 + quant_config: Optional[QuantizationConfig] = None,
98 + prefix: str = ""):
99 super().__init__(config,
100 num_experts=1,
101 top_k=1,
102 params_dtype=params_dtype,
103 tp_size=tp_size,
101 - quant_config=quant_config)
104 + quant_config=quant_config,
105 + prefix=prefix)
106
107
108 class JambaMambaDecoderLayer(nn.Module):
@@ -109,6 +113,7 @@ class JambaMambaDecoderLayer(nn.Module):
113 cache_config: Optional[CacheConfig] = None,
114 quant_config: Optional[QuantizationConfig] = None,
115 is_lora_enabled: Optional[bool] = False,
116 + prefix: str = "",
117 **kwargs) -> None:
118 super().__init__()
119 self.config = config
@@ -129,7 +134,9 @@ class JambaMambaDecoderLayer(nn.Module):
134
135 num_experts = config.layers_num_experts[layer_idx]
136 ffn_layer_class = JambaMoE if num_experts > 1 else JambaMLP
132 - self.feed_forward = ffn_layer_class(config, quant_config=quant_config)
137 + self.feed_forward = ffn_layer_class(config,
138 + quant_config=quant_config,
139 + prefix=f"{prefix}.feed_forward")
140 self.input_layernorm = RMSNorm(config.hidden_size,
141 eps=config.rms_norm_eps)
142 self.pre_ff_layernorm = RMSNorm(config.hidden_size,
@@ -211,7 +218,9 @@ class JambaAttentionDecoderLayer(nn.Module):
218
219 num_experts = config.layers_num_experts[layer_idx]
220 ffn_layer_class = JambaMoE if num_experts > 1 else JambaMLP
214 - self.feed_forward = ffn_layer_class(config, quant_config=quant_config)
221 + self.feed_forward = ffn_layer_class(config,
222 + quant_config=quant_config,
223 + prefix=f"{prefix}.feed_forward")
224 self.input_layernorm = RMSNorm(config.hidden_size,
225 eps=config.rms_norm_eps)
226 self.pre_ff_layernorm = RMSNorm(config.hidden_size,
vllm/model_executor/models/mixtral.py
+2
@@ -71,6 +71,7 @@ class MixtralMoE(nn.Module):
71 params_dtype: Optional[torch.dtype] = None,
72 quant_config: Optional[QuantizationConfig] = None,
73 tp_size: Optional[int] = None,
74 + dp_size: Optional[int] = None,
75 prefix: str = ""):
76 super().__init__()
77 self.hidden_size = hidden_size
@@ -93,6 +94,7 @@ class MixtralMoE(nn.Module):
94 renormalize=True,
95 quant_config=quant_config,
96 tp_size=tp_size,
97 + dp_size=dp_size,
98 prefix=f"{prefix}.experts")
99
100 def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
vllm/model_executor/models/olmoe.py
+3 -1
@@ -80,7 +80,8 @@ class OlmoeMoE(nn.Module):
80 reduce_results=True,
81 renormalize=False,
82 quant_config=quant_config,
83 - tp_size=tp_size)
83 + tp_size=tp_size,
84 + prefix=f"{prefix}.experts")
85
86 def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
87 # NOTE: hidden_states can have either 1D or 2D shape.
@@ -212,6 +213,7 @@ class OlmoeDecoderLayer(nn.Module):
213 hidden_size=config.hidden_size,
214 intermediate_size=config.intermediate_size,
215 quant_config=quant_config,
216 + prefix=f"{prefix}.mlp",
217 )
218 self.input_layernorm = RMSNorm(config.hidden_size, eps=1e-5)
219 self.post_attention_layernorm = RMSNorm(config.hidden_size, eps=1e-5)
vllm/model_executor/models/phimoe.py
+4 -1
@@ -249,6 +249,7 @@ class PhiMoE(nn.Module):
249 params_dtype: Optional[torch.dtype] = None,
250 quant_config: Optional[QuantizationConfig] = None,
251 tp_size: Optional[int] = None,
252 + prefix: str = "",
253 ):
254 super().__init__()
255 self.hidden_size = hidden_size
@@ -272,7 +273,8 @@ class PhiMoE(nn.Module):
273 renormalize=False,
274 quant_config=quant_config,
275 tp_size=tp_size,
275 - custom_routing_function=phimoe_routing_function)
276 + custom_routing_function=phimoe_routing_function,
277 + prefix=f"{prefix}.experts")
278
279 def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
280 # NOTE: hidden_states can have either 1D or 2D shape.
@@ -396,6 +398,7 @@ class PhiMoEDecoderLayer(nn.Module):
398 hidden_size=config.hidden_size,
399 intermediate_size=config.intermediate_size,
400 quant_config=quant_config,
401 + prefix=f"{prefix}.block_sparse_moe",
402 )
403 self.input_layernorm = nn.LayerNorm(config.hidden_size,
404 eps=config.rms_norm_eps,
vllm/model_executor/models/qwen2_moe.py
+5 -2
@@ -100,6 +100,7 @@ class Qwen2MoeSparseMoeBlock(nn.Module):
100 self,
101 config: PretrainedConfig,
102 quant_config: Optional[QuantizationConfig] = None,
103 + prefix: str = "",
104 ):
105 super().__init__()
106 self.tp_size = get_tensor_model_parallel_world_size()
@@ -115,7 +116,8 @@ class Qwen2MoeSparseMoeBlock(nn.Module):
116 intermediate_size=config.moe_intermediate_size,
117 reduce_results=False,
118 renormalize=config.norm_topk_prob,
118 - quant_config=quant_config)
119 + quant_config=quant_config,
120 + prefix=f"{prefix}.experts")
121
122 self.gate = ReplicatedLinear(config.hidden_size,
123 config.num_experts,
@@ -277,7 +279,8 @@ class Qwen2MoeDecoderLayer(nn.Module):
279 config.num_experts > 0 and
280 (layer_idx + 1) % config.decoder_sparse_step == 0):
281 self.mlp = Qwen2MoeSparseMoeBlock(config=config,
280 - quant_config=quant_config)
282 + quant_config=quant_config,
283 + prefix=f"{prefix}.mlp")
284 else:
285 self.mlp = Qwen2MoeMLP(
286 hidden_size=config.hidden_size,
vllm/platforms/cuda.py
+9
@@ -111,6 +111,7 @@ class CudaPlatformBase(Platform):
111 def check_and_update_config(cls, vllm_config: VllmConfig) -> None:
112 parallel_config = vllm_config.parallel_config
113 scheduler_config = vllm_config.scheduler_config
114 + compilation_config = vllm_config.compilation_config
115
116 if parallel_config.worker_cls == "auto":
117 if scheduler_config.is_multi_step:
@@ -150,6 +151,14 @@ class CudaPlatformBase(Platform):
151 "FlashMLA: Forcing kv cache block size to 64 since this"
152 " is currently the only block size supported by the kernel.")
153
154 + if (parallel_config.data_parallel_size > 1
155 + and compilation_config.use_cudagraph):
156 + logger.info(
157 + "Data Parallel: Forcing enforce eager to be True since DP is "
158 + "currently not supported with CUDA Graphs.")
159 + vllm_config.model_config.enforce_eager = True
160 + compilation_config.use_cudagraph = False
161 +
162 @classmethod
163 def get_current_memory_usage(cls,
164 device: Optional[torch.types.Device] = None
vllm/utils.py
+2 -2
@@ -2196,8 +2196,8 @@ def bind_kv_cache(
2196 from vllm.model_executor.models.utils import extract_layer_index
2197 layer_need_kv_cache = [
2198 layer_name for layer_name in ctx
2199 - if ctx[layer_name].attn_type in (AttentionType.DECODER,
2200 - AttentionType.ENCODER_DECODER)
2199 + if (hasattr(ctx[layer_name], 'attn_type') and ctx[layer_name].attn_type
2200 + in (AttentionType.DECODER, AttentionType.ENCODER_DECODER))
2201 ]
2202 layer_index_sorted = sorted(
2203 set(
vllm/v1/engine/core.py
-1
@@ -149,7 +149,6 @@ class EngineCore:
149 if not self.scheduler.has_unfinished_requests():
150 return EngineCoreOutputs(
151 outputs=[], scheduler_stats=self.scheduler.make_stats())
152 -
152 scheduler_output = self.scheduler.schedule()
153 output = self.model_executor.execute_model(scheduler_output)
154 engine_core_outputs = self.scheduler.update_from_output(
vllm/v1/worker/gpu_model_runner.py
+7 -3
@@ -17,6 +17,7 @@ from vllm.distributed.parallel_state import get_pp_group, graph_capture
17 from vllm.forward_context import set_forward_context
18 from vllm.inputs import INPUT_REGISTRY
19 from vllm.logger import init_logger
20 +from vllm.model_executor.layers.fused_moe import FusedMoE
21 from vllm.model_executor.layers.rotary_embedding import MRotaryEmbedding
22 from vllm.model_executor.model_loader import get_model
23 from vllm.multimodal import MULTIMODAL_REGISTRY, MultiModalKwargs
@@ -1357,7 +1358,7 @@ class GPUModelRunner(LoRAModelRunnerMixin):
1358 """
1359 Initialize KV cache based on `kv_cache_config`.
1360 Args:
1360 - kv_cache_config: Configuration for the KV cache, including the KV
1361 + kv_cache_config: Configuration for the KV cache, including the KV
1362 cache size of each layer
1363 """
1364 if len(kv_cache_config.groups) > 1:
@@ -1389,10 +1390,10 @@ class GPUModelRunner(LoRAModelRunnerMixin):
1390
1391 def get_kv_cache_spec(self) -> KVCacheSpec:
1392 """
1392 - Generates the KVCacheSpec by parsing the kv cache format from each
1393 + Generates the KVCacheSpec by parsing the kv cache format from each
1394 Attention module in the static forward context.
1395 Returns:
1395 - KVCacheSpec: A dictionary mapping layer names to their KV cache
1396 + KVCacheSpec: A dictionary mapping layer names to their KV cache
1397 format. Layers that do not need KV cache are not included.
1398 """
1399
@@ -1400,6 +1401,9 @@ class GPUModelRunner(LoRAModelRunnerMixin):
1401 block_size = self.vllm_config.cache_config.block_size
1402 kv_cache_spec: KVCacheSpec = {}
1403 for layer_name, attn_module in forward_ctx.items():
1404 + if isinstance(attn_module, FusedMoE):
1405 + continue
1406 +
1407 # TODO: Support other attention modules, e.g., sliding window,
1408 # cross-attention, MLA.
1409 assert isinstance(attn_module, Attention)