@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 8e38e99829
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 12, 22:15 UTC

[Feature] EPLB on Qwen3VLMoe and CompressedTensorsWNA16MoEMethod (#28849)

JartX committed Nov 20, 2025 at 00:30 UTC 8e38e998298364b0a94cddf7ccc59d8466c2396a
2 files changed +82 -7
vllm/model_executor/layers/quantization/compressed_tensors/compressed_tensors_moe.py
+24 -3
@@ -1921,9 +1921,20 @@ class CompressedTensorsWNA16MoEMethod(CompressedTensorsMoEMethod):
1921 logical_replica_count: torch.Tensor | None = None,
1922 ) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
1923 if enable_eplb:
1924 - raise NotImplementedError(
1925 - "EPLB not supported for `CompressedTensorsWNA16MoEMethod` yet."
1926 - )
1924 + if expert_load_view is None:
1925 + raise ValueError("enable_eplb=True requiere expert_load_view != None")
1926 + if logical_to_physical_map is None:
1927 + raise ValueError(
1928 + "enable_eplb=True requiere logical_to_physical_map != None"
1929 + )
1930 + if logical_replica_count is None:
1931 + raise ValueError(
1932 + "enable_eplb=True requiere logical_replica_count != None"
1933 + )
1934 + if not isinstance(layer, FusedMoE):
1935 + raise TypeError(
1936 + "EPLB is only supported when `layer` is a instance of FusedMoE."
1937 + )
1938
1939 from vllm.model_executor.layers.fused_moe import fused_experts
1940
@@ -1940,6 +1951,12 @@ class CompressedTensorsWNA16MoEMethod(CompressedTensorsMoEMethod):
1951 routed_scaling_factor=routed_scaling_factor,
1952 e_score_correction_bias=e_score_correction_bias,
1953 indices_type=self.topk_indices_dtype,
1954 + num_fused_shared_experts=getattr(layer, "num_fused_shared_experts", 0),
1955 + enable_eplb=enable_eplb,
1956 + expert_map=expert_map,
1957 + expert_load_view=expert_load_view,
1958 + logical_to_physical_map=logical_to_physical_map,
1959 + logical_replica_count=logical_replica_count,
1960 )
1961
1962 return fused_experts(
@@ -1956,6 +1973,10 @@ class CompressedTensorsWNA16MoEMethod(CompressedTensorsMoEMethod):
1973 quant_config=self.moe_quant_config,
1974 )
1975
1976 + @property
1977 + def supports_eplb(self) -> bool:
1978 + return True
1979 +
1980
1981 class CompressedTensorsW4A8Int8MoEMethod(CompressedTensorsMoEMethod):
1982 """
vllm/model_executor/models/qwen3_vl_moe.py
+58 -4
@@ -15,7 +15,7 @@
15 # you may not use this file except in compliance with the License.
16 # You may obtain a copy of the License at
17 #
18 -# http://www.apache.org/licenses/LICENSE-2.0
18 +# http://www.apache.org/licenses/LICENSE-2.0
19 #
20 # Unless required by applicable law or agreed to in writing, software
21 # distributed under the License is distributed on an "AS IS" BASIS,
@@ -29,7 +29,9 @@ from collections.abc import Callable, Iterable
29 from itertools import islice
30
31 import torch
32 -from transformers.models.qwen3_vl_moe.configuration_qwen3_vl_moe import Qwen3VLMoeConfig
32 +from transformers.models.qwen3_vl_moe.configuration_qwen3_vl_moe import (
33 + Qwen3VLMoeConfig,
34 +)
35
36 from vllm.compilation.decorators import support_torch_compile
37 from vllm.config import VllmConfig
@@ -44,7 +46,12 @@ from vllm.model_executor.model_loader.weight_utils import (
46 from vllm.multimodal import MULTIMODAL_REGISTRY
47 from vllm.sequence import IntermediateTensors
48
47 -from .qwen3_moe import Qwen3MoeForCausalLM, Qwen3MoeModel
49 +from .interfaces import MixtureOfExperts
50 +from .qwen3_moe import (
51 + Qwen3MoeForCausalLM,
52 + Qwen3MoeModel,
53 + Qwen3MoeSparseMoeBlock,
54 +)
55 from .qwen3_vl import (
56 Qwen3_VisionTransformer,
57 Qwen3VLDummyInputsBuilder,
@@ -344,12 +351,56 @@ class Qwen3MoeLLMForCausalLM(Qwen3MoeForCausalLM):
351 )
352
353
354 +class Qwen3VLMoeMixtureOfExperts(MixtureOfExperts):
355 + def update_physical_experts_metadata(
356 + self,
357 + num_physical_experts: int,
358 + num_local_physical_experts: int,
359 + ) -> None:
360 + assert self.num_local_physical_experts == num_local_physical_experts
361 + self.num_physical_experts = num_physical_experts
362 + self.num_local_physical_experts = num_local_physical_experts
363 + self.num_redundant_experts = num_physical_experts - self.num_logical_experts
364 + for layer in self.language_model.model.layers:
365 + if isinstance(layer.mlp, Qwen3MoeSparseMoeBlock):
366 + moe = layer.mlp
367 + moe.n_local_physical_experts = num_local_physical_experts
368 + moe.n_physical_experts = num_physical_experts
369 + moe.n_redundant_experts = self.num_redundant_experts
370 + moe.experts.update_expert_map()
371 +
372 + def set_moe_parameters(self):
373 + self.expert_weights = []
374 +
375 + self.moe_layers = []
376 + example_moe = None
377 + for layer in self.language_model.model.layers:
378 + if hasattr(layer, "mlp") and isinstance(layer.mlp, Qwen3MoeSparseMoeBlock):
379 + example_moe = layer.mlp
380 + self.moe_layers.append(layer.mlp.experts)
381 +
382 + if example_moe is None:
383 + raise RuntimeError("No Qwen3Moe layer found in the language_model.")
384 +
385 + # Set MoE hyperparameters
386 + self.num_moe_layers = len(self.moe_layers)
387 + self.num_expert_groups = 1
388 + self.num_shared_experts = 0
389 + self.num_logical_experts = example_moe.n_logical_experts
390 + self.num_physical_experts = example_moe.n_physical_experts
391 + self.num_local_physical_experts = example_moe.n_local_physical_experts
392 + self.num_routed_experts = example_moe.n_routed_experts
393 + self.num_redundant_experts = example_moe.n_redundant_experts
394 +
395 +
396 @MULTIMODAL_REGISTRY.register_processor(
397 Qwen3VLMultiModalProcessor,
398 info=Qwen3VLMoeProcessingInfo,
399 dummy_inputs=Qwen3VLDummyInputsBuilder,
400 )
352 -class Qwen3VLMoeForConditionalGeneration(Qwen3VLForConditionalGeneration):
401 +class Qwen3VLMoeForConditionalGeneration(
402 + Qwen3VLForConditionalGeneration, Qwen3VLMoeMixtureOfExperts
403 +):
404 packed_modules_mapping = {
405 "qkv_proj": [
406 "q_proj",
@@ -413,3 +464,6 @@ class Qwen3VLMoeForConditionalGeneration(Qwen3VLForConditionalGeneration):
464 self.deepstack_input_embeds = None
465 self.visual_dim = config.vision_config.out_hidden_size
466 self.multiscale_dim = self.visual_dim * self.deepstack_num_level
467 +
468 + # Set MoE hyperparameters
469 + self.set_moe_parameters()