@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 67bc0c003e
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 14, 05:30 UTC

[Bugfix] Fix qwen3 vl dummy data generation with overrides (#26193)

Signed-off-by: Roger Wang <hey@rogerw.io>

Roger Wang committed Oct 3, 2025 at 18:40 UTC 67bc0c003eca6758b24d6e02e4fb285b33d9f028
1 file changed +43 -20
vllm/model_executor/models/qwen3_vl.py
+43 -20
@@ -47,7 +47,7 @@ from vllm.attention.backends.registry import _Backend
47 from vllm.attention.layer import check_upstream_fa_availability
48 from vllm.compilation.decorators import support_torch_compile
49 from vllm.config import VllmConfig
50 -from vllm.config.multimodal import BaseDummyOptions
50 +from vllm.config.multimodal import BaseDummyOptions, VideoDummyOptions
51 from vllm.distributed import get_pp_group
52 from vllm.logger import init_logger
53 from vllm.model_executor.layers.activation import _ACTIVATION_REGISTRY
@@ -741,20 +741,57 @@ class Qwen3VLDummyInputsBuilder(BaseDummyInputsBuilder[Qwen3VLProcessingInfo]):
741 ) -> MultiModalDataDict:
742 num_images = mm_counts.get("image", 0)
743 num_videos = mm_counts.get("video", 0)
744 + image_overrides = mm_options.get("image") if mm_options else None
745 + video_overrides = mm_options.get("video") if mm_options else None
746
747 target_width, target_height = (
748 self.info.get_image_size_with_most_features())
749 target_num_frames = self.info.get_num_frames_with_most_features(
750 seq_len, mm_counts)
751 +
752 + if video_overrides:
753 + assert isinstance(video_overrides, VideoDummyOptions)
754 + num_frames_override = video_overrides.num_frames
755 + if num_frames_override:
756 + if num_frames_override > target_num_frames:
757 + logger.warning(
758 + "video.num_frames override (%d) exceeds model's "
759 + "maximum number of frames (%d), will be ignored",
760 + num_frames_override, target_num_frames)
761 + if num_frames_override < 2:
762 + logger.warning(
763 + "video.num_frames override (%d) cannot be less "
764 + "than 2, will be ignored", num_frames_override)
765 + target_num_frames = min(target_num_frames, num_frames_override)
766 + target_num_frames = max(target_num_frames, 2)
767 +
768 target_video_size, _ = self.info._get_vision_info(
769 image_width=target_width,
770 image_height=target_height,
771 num_frames=target_num_frames,
772 image_processor=self.info.get_video_processor(),
773 )
755 -
756 - image_overrides = mm_options.get("image") if mm_options else None
757 - video_overrides = mm_options.get("video") if mm_options else None
774 + # NOTE: we need to do this check here since Qwen3-VL resizes video
775 + # frames depending on how many frames there are.
776 + width, height = target_video_size.width, target_video_size.height
777 + if video_overrides:
778 + assert isinstance(video_overrides, VideoDummyOptions)
779 + width_override = video_overrides.width
780 + if width_override:
781 + if width_override > width:
782 + logger.warning(
783 + "video.width override (%d) exceeds model's "
784 + "maximum width (%d), will be ignored", width_override,
785 + width)
786 + width = min(width, width_override)
787 + height_override = video_overrides.height
788 + if height_override:
789 + if height_override > height:
790 + logger.warning(
791 + "video.height override (%d) exceeds model's "
792 + "maximum height (%d), will be ignored",
793 + height_override, height)
794 + height = min(height, height_override)
795
796 return {
797 "image":
@@ -764,11 +801,10 @@ class Qwen3VLDummyInputsBuilder(BaseDummyInputsBuilder[Qwen3VLProcessingInfo]):
801 overrides=image_overrides),
802 "video":
803 self._get_dummy_videos(
767 - width=target_video_size.width,
768 - height=target_video_size.height,
804 + width=width,
805 + height=height,
806 num_frames=target_num_frames,
807 num_videos=num_videos,
771 - overrides=video_overrides,
808 ),
809 }
810
@@ -780,7 +816,6 @@ class Qwen3VLDummyInputsBuilder(BaseDummyInputsBuilder[Qwen3VLProcessingInfo]):
816 num_frames: int,
817 num_videos: int,
818 ) -> list[VideoItem]:
783 - num_frames = max(num_frames, 2)
819 video = np.full((num_frames, width, height, 3), 255, dtype=np.uint8)
820 video_items = []
821 for i in range(num_videos):
@@ -796,18 +831,6 @@ class Qwen3VLDummyInputsBuilder(BaseDummyInputsBuilder[Qwen3VLProcessingInfo]):
831 video_items.append(video_item)
832 return video_items
833
799 - def get_dummy_processor_inputs(self, seq_len, mm_counts):
800 - processor_inputs = super().get_dummy_processor_inputs(
801 - seq_len, mm_counts)
802 - # HACK(Isotr0py): We set do_resize to False here to reuse Qwen2-VL's
803 - # profiling logic, which will be problematic for configurable mm
804 - # profiling.
805 - # TODO(Isotr0py): Switch to the implementation in
806 - # https://github.com/vllm-project/vllm/pull/25557
807 - # after supporting configurable mm profiling.
808 - processor_inputs.hf_processor_mm_kwargs = {"do_resize": False}
809 - return processor_inputs
810 -
834
835 class Qwen3VLMultiModalProcessor(BaseMultiModalProcessor[Qwen3VLProcessingInfo]
836 ):