[Model] Enable EVS for Qwen3.5 (#48912)
Signed-off-by: Rui "Garry" Gao <garrygaogg@gmail.com>
Rui "Garry" Gao committed
Jul 27, 2026 at 21:42 UTC
dbccc5ae328d7b9168bc33b278a9125cfd89cc69
1 file changed
+32
-12
vllm/model_executor/models/qwen3_5.py
+32
-12
@@ -53,6 +53,7 @@ from vllm.model_executor.layers.vocab_parallel_embedding import (
53
)
54
from vllm.multimodal import MULTIMODAL_REGISTRY
55
from vllm.sequence import IntermediateTensors
56
+from vllm.tokenizers.registry import cached_tokenizer_from_config
57
from vllm.transformers_utils.configs.qwen3_5 import Qwen3_5Config, Qwen3_5TextConfig
58
from vllm.transformers_utils.configs.qwen3_5_moe import (
59
Qwen3_5MoeConfig,
@@ -397,8 +398,7 @@ class Qwen3_5MoeForCausalLM(Qwen3_5ForCausalLMBase, QwenNextMixtureOfExperts):
398
dummy_inputs=Qwen3VLDummyInputsBuilder,
399
)
400
class Qwen3_5ForConditionalGeneration(Qwen3VLForConditionalGeneration, IsHybrid):
400
- # Qwen3.5 does not support multimodal pruning (EVS).
401
- supports_multimodal_pruning = False
401
+ supports_multimodal_pruning = True
402
403
packed_modules_mapping = Qwen3VLForConditionalGeneration.packed_modules_mapping | {
404
"in_proj_qkvz": ["in_proj_qkv", "in_proj_z"],
@@ -416,8 +416,21 @@ class Qwen3_5ForConditionalGeneration(Qwen3VLForConditionalGeneration, IsHybrid)
416
self.model_config = vllm_config.model_config
417
self.multimodal_config = multimodal_config
418
self.use_data_parallel = multimodal_config.mm_encoder_tp_mode == "data"
419
- # Qwen3.5 does not support multimodal pruning (EVS).
420
- self.is_multimodal_pruning_enabled = False
419
+ self.is_multimodal_pruning_enabled = (
420
+ multimodal_config.is_multimodal_pruning_enabled()
421
+ )
422
+ self.video_pruning_rate = self.multimodal_config.video_pruning_rate
423
+ self._tokenizer = cached_tokenizer_from_config(vllm_config.model_config)
424
+
425
+ # attributes needed by EVS-related functions inherited from Qwen3-VL
426
+ self.use_deepstack = hasattr(config.vision_config, "deepstack_visual_indexes")
427
+ self.deepstack_num_level = (
428
+ len(config.vision_config.deepstack_visual_indexes)
429
+ if self.use_deepstack
430
+ else 0
431
+ )
432
+ self.visual_dim = config.vision_config.out_hidden_size
433
+ self.multiscale_dim = self.visual_dim * self.deepstack_num_level
434
435
with self._mark_tower_model(vllm_config, {"image", "video"}):
436
self.visual = Qwen3_VisionTransformer(
@@ -462,12 +475,6 @@ class Qwen3_5ForConditionalGeneration(Qwen3VLForConditionalGeneration, IsHybrid)
475
476
return inputs_embeds
477
465
- def recompute_mrope_positions(self, *args, **kwargs):
466
- raise NotImplementedError(
467
- "Qwen3.5 does not support multimodal pruning (EVS). "
468
- "recompute_mrope_positions should never be called."
469
- )
470
-
478
def forward(
479
self,
480
input_ids: torch.Tensor,
@@ -628,8 +635,21 @@ class Qwen3_5MoeForConditionalGeneration(
635
self.model_config = vllm_config.model_config
636
self.multimodal_config = multimodal_config
637
self.use_data_parallel = multimodal_config.mm_encoder_tp_mode == "data"
631
- # Qwen3.5 does not support multimodal pruning (EVS).
632
- self.is_multimodal_pruning_enabled = False
638
+ self.is_multimodal_pruning_enabled = (
639
+ multimodal_config.is_multimodal_pruning_enabled()
640
+ )
641
+ self.video_pruning_rate = self.multimodal_config.video_pruning_rate
642
+ self._tokenizer = cached_tokenizer_from_config(vllm_config.model_config)
643
+
644
+ # attributes needed by EVS-related functions inherited from Qwen3-VL
645
+ self.use_deepstack = hasattr(config.vision_config, "deepstack_visual_indexes")
646
+ self.deepstack_num_level = (
647
+ len(config.vision_config.deepstack_visual_indexes)
648
+ if self.use_deepstack
649
+ else 0
650
+ )
651
+ self.visual_dim = config.vision_config.out_hidden_size
652
+ self.multiscale_dim = self.visual_dim * self.deepstack_num_level
653
654
with self._mark_tower_model(vllm_config, {"image", "video"}):
655
self.visual = Qwen3_VisionTransformer(