Skip to content

[Bugfix][Model Runner V2] Restore multimodal draft capability detection - #50417

Merged
njhill merged 8 commits into
vllm-project:mainfrom
TQCB:rraph/fix-mrv2-spec-mm-capability
Aug 3, 2026
Merged

[Bugfix][Model Runner V2] Restore multimodal draft capability detection#50417
njhill merged 8 commits into
vllm-project:mainfrom
TQCB:rraph/fix-mrv2-spec-mm-capability

Conversation

@TQCB

@TQCB TQCB commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Purpose

Separate the target model ability to produce multimodal embeddings from the drafter ability to consume them.

Changes

  • Add a SupportsMultiModalEmbeddings protocol and typed capability helper.
  • Make SupportsMultiModal inherit the protocol.
  • Explicitly implement it on supported Eagle and Inkling drafters.
  • Centralize capability detection and fallback warnings in DraftModelSpeculator.load_model().
  • Allocate embedding buffers only after the loaded drafter capability is known.
  • Remove the Inkling model-type hack.
  • Leave signature-only drafters such as Eagle3LlamaForCausalLM unmarked.

Validation

pytest tests/v1/worker/test_gpu_autoregressive_speculator.py -q
11 passed

pre-commit on changed files
passed, including ruff and mypy

Model evals were not run; no model implementation or model math changed.

Duplicate check

No open PR implements this capability contract. #36097 propagates multimodal embeddings but does not provide explicit drafter capability detection.

AI assistance

Prepared with assistance from OpenAI Codex; the human submitter reviewed the changes.

@mergify mergify Bot added v1 bug Something isn't working labels Jul 30, 2026

@NickLucche NickLucche left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we do supports_multimodal here or similar reflection mechanisms? @DarkLight1337

Comment on lines +59 to +71
try:
dummy_input_ids = torch.tensor([[1]], device=self.device)
self.model.embed_input_ids(
dummy_input_ids,
multimodal_embeddings=None,
is_multimodal=None,
)
except (NotImplementedError, AttributeError, TypeError):
logger.warning(
"Draft model does not support multimodal inputs, "
"falling back to text-only mode"
)
self.supports_mm_inputs = False

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we spare the dummy forward here (trying to centralize everything into profiling run), and instead rely on self.model class inspection here ?

@TheEpicDolphin

TheEpicDolphin commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the fix @TQCB. Like Nick suggested, I think it would be better to use supports_multimodal like how it's done here:

self.supports_mm: bool = (
supports_multimodal(self.model)
# In case the model only supports LoRA for
# text modules (e.g. ChatGLM)
and hasattr(self.model, "get_mm_mapping")
)
, rather than invoking embed_input_ids.

@mergify mergify Bot added the mrv2 Model Runner V2 specific label Jul 31, 2026
@TQCB

TQCB commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

better to use supports_multimodal

@TheEpicDolphin This would indeed be better, but supports_multimodal depends on either:

  • the draft model inheriting SupportsMultiModal
  • or explicitly setting the supports_multimodal attribute which is what is actually checked

Neither of these are the case for most draft models. There is a hacky solution which would be:

signature(self.model.embed_input_ids).bind(
          None,
          multimodal_embeddings=None,
          is_multimodal=None,
      )

but I would prefer having a more explicit contract, rather than relying on this ad hoc check. Ideally there would be an advertized supports_multimodal_embeddings capability declared by draft models for us to use here.

@DarkLight1337

Copy link
Copy Markdown
Member

Ideally there would be an advertized supports_multimodal_embeddings capability declared by draft models for us to use here.

Yeah I prefer this approach as well

@mergify mergify Bot added llama Related to Llama models speculative-decoding mistral Related to Mistral models labels Aug 3, 2026
@TQCB
TQCB marked this pull request as ready for review August 3, 2026 09:42

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@TQCB

TQCB commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Hello @NickLucche @TheEpicDolphin @DarkLight1337 , I've updated the PR to use a supports_multimodal_embeddings flag for the drafters. I've updated the following models to support this:

  • EagleLlama4ForCausalLM
  • EagleMistralForCausalLM
  • EagleMistralLarge3ForCausalLM

These are the models I found merged external mm embeddings and don't already inherit SupportsMultiModal. Let me know if there are any others I'm missing.

Comment thread vllm/model_executor/models/interfaces.py Outdated
@TQCB

TQCB commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Updated to use a protocol instead

@TQCB
TQCB requested a review from DarkLight1337 August 3, 2026 14:17

@DarkLight1337 DarkLight1337 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The interface LGTM, but @njhill @ywang96 should take a look at the MRv2 part

@njhill njhill left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @TQCB! Looks good to me overall, just couple of minor comments.

Could we make the same changes here

self.supports_mm_inputs = MULTIMODAL_REGISTRY.supports_multimodal_inputs(
self.draft_model_config
)
# HACK: the Inkling MTP draft has no MM processor of its own (its draft
# config is flattened text-only), but it consumes the target's merged
# embeddings at draft prefill — treat it as MM-capable whenever the
# target is.
if (
not self.supports_mm_inputs
and self.draft_model_config.hf_config.model_type == "inkling_mtp"
):
self.supports_mm_inputs = MULTIMODAL_REGISTRY.supports_multimodal_inputs(
vllm_config.model_config
)
self.inputs_embeds: torch.Tensor | None = None
if self.supports_mm_inputs:
self.inputs_embeds = torch.zeros(
self.max_num_tokens, self.hidden_size, dtype=self.dtype, device=device
)
, and this can be used to remove the Inkling hack :)

Comment on lines 48 to 50

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be moved to load_model to avoid allocating unnecessarily

In fact would it now make sense to move all of the self.support_mm_inputs logic into load_model?

TQCB added 5 commits August 3, 2026 18:14
Assisted-by: Codex

Signed-off-by: Raphael Rialland <raphael.rialland@mistral.ai>
Assisted-by: Codex

Signed-off-by: Raphael Rialland <raphael.rialland@mistral.ai>
Assisted-by: Codex

Signed-off-by: Raphael Rialland <raphael.rialland@mistral.ai>
Assisted-by: Codex

Signed-off-by: Raphael Rialland <raphael.rialland@mistral.ai>
Assisted-by: Codex

Signed-off-by: Raphael Rialland <raphael.rialland@mistral.ai>
TQCB added 3 commits August 3, 2026 18:14
Assisted-by: Codex

Signed-off-by: Raphael Rialland <raphael.rialland@mistral.ai>
Assisted-by: Codex

Signed-off-by: Raphael Rialland <raphael.rialland@mistral.ai>
Assisted-by: Codex

Signed-off-by: Raphael Rialland <raphael.rialland@mistral.ai>
@TQCB
TQCB force-pushed the rraph/fix-mrv2-spec-mm-capability branch from 9a5dc44 to 3d13da1 Compare August 3, 2026 16:30
@TQCB

TQCB commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the comments @njhill . I've moved the support check to the parent, and now all the children just check the flag and allocate the buffers they need based on the result. This feels pretty clean to me, LMK what you think!

@njhill njhill left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @TQCB LGTM!

cc @TheEpicDolphin @benchislett re the final structure

@njhill njhill added the ready ONLY add when PR is ready to merge/full CI is needed label Aug 3, 2026
@njhill
njhill merged commit 4a3447d into vllm-project:main Aug 3, 2026
121 of 122 checks passed
@TQCB
TQCB deleted the rraph/fix-mrv2-spec-mm-capability branch August 4, 2026 07:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working llama Related to Llama models mistral Related to Mistral models mrv2 Model Runner V2 specific ready ONLY add when PR is ready to merge/full CI is needed speculative-decoding v1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants