From 2addbb9cc97e2f75165ab3b81c4287a1dd8a5b0c Mon Sep 17 00:00:00 2001 From: Ruinan Ma <97484148+mrn3088@users.noreply.github.com> Date: Mon, 15 Jun 2026 21:12:54 -0700 Subject: [PATCH] [BugFix] Support async scheduling with prompt embeds for multimodal models (#45673) Signed-off-by: Ruinan Ma --- vllm/config/vllm.py | 19 ------------------- vllm/v1/worker/gpu_model_runner.py | 6 +++++- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/vllm/config/vllm.py b/vllm/config/vllm.py index 95e299eb02..98ec40e860 100644 --- a/vllm/config/vllm.py +++ b/vllm/config/vllm.py @@ -966,15 +966,6 @@ class VllmConfig: "Async scheduling is not compatible with " "disable_padded_drafter_batch=True." ) - if ( - self.model_config is not None - and self.model_config.enable_prompt_embeds - and self.model_config.is_multimodal_model - ): - raise ValueError( - "Async scheduling is not yet supported with prompt embeds " - "for multimodal models." - ) if not executor_supports_async_sched: raise ValueError( f"`{executor_backend}` does not support async scheduling yet." @@ -1018,16 +1009,6 @@ class VllmConfig: executor_backend, ) self.scheduler_config.async_scheduling = False - elif ( - self.model_config is not None - and self.model_config.enable_prompt_embeds - and self.model_config.is_multimodal_model - ): - logger.warning_once( - "Async scheduling is not yet supported with prompt embeds " - "for multimodal models and will be disabled." - ) - self.scheduler_config.async_scheduling = False else: self.scheduler_config.async_scheduling = True diff --git a/vllm/v1/worker/gpu_model_runner.py b/vllm/v1/worker/gpu_model_runner.py index fc6608e5d6..b958ef79d0 100644 --- a/vllm/v1/worker/gpu_model_runner.py +++ b/vllm/v1/worker/gpu_model_runner.py @@ -1779,13 +1779,17 @@ class GPUModelRunner( num_common_tokens = len(sample_flattened_indices) total_without_spec = total_num_scheduled_tokens - total_num_spec_tokens + if self.enable_prompt_embeds: + # The multimodal embed path reads is_token_ids.gpu; its .cpu copy is + # refreshed every step but the async fast paths below only scatter + # input_ids.gpu, so refresh is_token_ids.gpu here too. + self.is_token_ids.copy_to_gpu(total_num_scheduled_tokens) if num_common_tokens < total_without_spec: # If not all requests are decodes from the last iteration, # we need to copy the input_ids_cpu to the GPU first. self.input_ids.copy_to_gpu(total_num_scheduled_tokens) if self.enable_prompt_embeds: self.inputs_embeds.copy_to_gpu(total_num_scheduled_tokens) - self.is_token_ids.copy_to_gpu(total_num_scheduled_tokens) if num_common_tokens == 0: # No requests in common with the previous iteration # So input_ids.cpu will have all the input ids.