Skip to content

fix: fix vlm cuda graph shape stability - #30868

Merged
mickqian merged 8 commits into
sgl-project:mainfrom
mickqian:codex/vlm-graph-shape-stability
Jul 19, 2026
Merged

mickqian merged 8 commits into
sgl-project:mainfrom
mickqian:codex/vlm-graph-shape-stability

Conversation

@mickqian

@mickqian mickqian commented Jul 11, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • mark mRoPE/ForwardBatch runtime token axes selectively dynamic for piecewise CUDA graphs
  • warm Qwen3-VL deepstack’s image-only decoder branch during startup
  • make ViT graph capture use an eager rotary helper and cache FA3 max-sequence metadata safely
  • safely fall back to eager execution if a replacement backend is instantiated without a capture stream

Before / after behavior

Qwen3-VL-32B-Instruct on H100 TP=4, with 128/256/512-pixel image requests: before, the first request at each unseen visual-token length created a PCG/Dynamo replacement compilation and its visible first-request pause. after, the startup-warmed graph is reused across that sweep (__recompiles=0). This is a first-request latency-stability result; no steady-state latency uplift is claimed.

Validation

  • PYTHONPATH=python pytest -q test/registered/unit/compilation/test_torch_compile_decoration.py (3 passed)
  • pre-commit on all changed files
  • registered regression coverage for raw cu_seqlens, piecewise fallback, and CUDA graph behavior.

CI States

Latest PR Test (Base): ❌ Run #29639402817
Latest PR Test (Extra): ❌ Run #29639402686

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces optimizations and fixes for compiling multimodal models (such as Qwen3-VL), including dynamic dimension marking for mRoPE token positions, a dummy forward pass to warm up deepstack embeddings, and an eager fallback for rotary embeddings during CUDA graph capture. Feedback on these changes highlights a critical bug in resolve_max_seqlen where passing a raw torch.Tensor will cause an AttributeError, a performance concern regarding the global use of dynamic=True in torch.compile which prevents kernel specialization, and unreachable dead code left behind by the generalized stream fallback in the CUDA piecewise backend.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@mickqian

Copy link
Copy Markdown
Collaborator Author

CI collection failure comes from the MoE pytest file introduced by sibling #30866, not from this PR’s diff. I added the required standalone __main__ entry in mickqian/sglang@88248d5ce1 and verified the exact python3 test/registered/unit/layers/moe/test_fused_moe_triton_config.py -f invocation on CUDA (2 passed). #30866 will re-run with the fix.

@mickqian

Copy link
Copy Markdown
Collaborator Author

/tag-and-rerun-ci

@github-actions github-actions Bot added the run-ci CI: run the baseline test suite on this PR label Jul 11, 2026
@mickqian
mickqian force-pushed the codex/vlm-graph-shape-stability branch from 5338e54 to 1bba625 Compare July 13, 2026 00:42
@mickqian mickqian changed the title Fix VLM CUDA graph shape stability fix: fix vlm cuda graph shape stability Jul 13, 2026
@mickqian
mickqian force-pushed the codex/vlm-graph-shape-stability branch from c2422dc to 7ebaf72 Compare July 17, 2026 03:13
@mickqian
mickqian merged commit d4801be into sgl-project:main Jul 19, 2026
304 of 341 checks passed
attn_backend.init_forward_metadata(fb)
self._run_forward(fb, num_tokens)

def run_dummy_multimodal_deepstack_forward(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this looks hacky.

  1. do we really need it?
  2. this is only for tc_piecewise backend, can we move it under python/sglang/srt/model_executor/runner_backend/tc_piecewise_cuda_graph_backend.py
  3. btw, we are going to deprecate tc_piecewise backend soon in favor of breakable backend. why do you still need to fix it for tc_piecewise?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

  1. yes deepstack is only for qwen-vl but it also brings solid performance gain
  2. sure
  3. I previous have no context of that, will shift to bcg from now on

Zhylkaaa pushed a commit to Zhylkaaa/sglang that referenced this pull request Jul 29, 2026
bowenwan6 added a commit to bowenwan6/sglang that referenced this pull request Aug 5, 2026
Qwen3-VL routes an ``input_deepstack_embeds`` kwarg to the language
model's forward on image requests. Under breakable-CUDA-graph replay
the tensor was silently dropped: the captured graph never traced the
DeepStack ``add_`` branch, and ``replay_layer_forward`` did not copy
the live tensor anywhere, so image outputs on any DeepStack-carrying
model on the BCG allowlist matched a zero-DeepStack run instead of
the eager reference. No shipped configuration triggers this today
(``Qwen/Qwen3.5-*`` releases ship with ``deepstack_visual_indexes=[]``
and Qwen3-VL is not on ``multimodal_breakable_cuda_graph_supported_model_archs``),
so this is a latent regression that would activate on either config
change; closing it defensively removes the trap.

Fix mirrors the existing ``input_embeds`` slot-and-copy pattern:

  * ``Qwen3VLForConditionalGeneration`` declares an explicit class
    attribute ``supports_bcg_deepstack_replay = True``. Its MoE
    subclass ``Qwen3VLMoeForConditionalGeneration`` inherits the flag.
    Non-Qwen3-VL archs (Qwen2.5-VL, Qwen3, Cohere2Vision, KimiK25,
    MiniMaxM3) do not set the attribute and default to ``False`` via
    ``getattr``.
  * ``PrefillCudaGraphRunner.__init__`` computes
    ``deepstack_replay_width = hidden_size × num_deepstack_embeddings``
    only when the capability flag is ``True`` AND the instance reports
    ``num_deepstack_embeddings > 0`` — otherwise ``0``. The width is
    passed to both ``PrefillInputBuffers.create`` (which allocates a
    single ``[max_num_tokens, width]`` bf16 buffer) and
    ``build_prefill_registry`` (which registers the matching optional
    ``GraphSlot``).
  * ``_run_forward``'s BCG capture branch passes the slot buffer as
    the ``input_deepstack_embeds`` kwarg when ``has_slot`` reports the
    slot is registered, so Dynamo traces the ``add_`` branch into the
    captured graph. Otherwise it falls through to today's four-
    positional call unchanged.
  * ``replay_layer_forward`` mirrors the ``input_embeds`` copy: when
    the slot is registered, it validates the live kwarg (present,
    ``numel() > 0``, matching per-row shape, dtype, device) and copies
    into the slot with a zeroed padded tail; missing / empty /
    mismatched inputs land in an ``else`` branch that zeros the whole
    slice so a stale image contribution cannot leak across bucket-
    reuse into a text-only request.

Zero cost for models that do not declare the capability: no
``PrefillInputBuffers`` field allocated, no registry slot, no
captured-graph kwarg, no replay-side copy — the entire block is
guarded by ``has_slot()``.

Refs sgl-project#30868 (PCG DeepStack Dynamo warmup) and sgl-project#30872 (input_embeds
BCG slot). Preserves ``run_dummy_multimodal_deepstack_forward`` for
the TC piecewise path unchanged.
Chronostasys pushed a commit to MindLab-Research/sglang that referenced this pull request Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Multi-modal multi-modal language model piecewise-cuda-graph run-ci CI: run the baseline test suite on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants