Skip to content

feat(multimodal): migrate Qwen3.5-VL to HybridModel - #6315

Draft
BestJuly wants to merge 1 commit into
NVIDIA:devfrom
BestJuly:lit/multimodal_hybrid
Draft

feat(multimodal): migrate Qwen3.5-VL to HybridModel#6315
BestJuly wants to merge 1 commit into
NVIDIA:devfrom
BestJuly:lit/multimodal_hybrid

Conversation

@BestJuly

@BestJuly BestJuly commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

What

Migrate the examples/multimodal_dev Qwen3.5-VL language decoder from
GPTModel to HybridModel, ahead of the deprecation of the GPTModel code path.

Why

The Qwen3.5-VL decoder is a hybrid GatedDeltaNet / full-attention stack. On the
GPT path that structure was expressed implicitly through
--experimental-attention-variant gated_delta_net plus
--linear-attention-freq 4, with the attention/MLP ordering baked into
TransformerLayer. HybridModel expresses it explicitly through
--hybrid-layer-pattern, which is where this model family belongs long term.

Changes

Model wiring (examples/multimodal_dev)

  • MultimodalModel / Qwen35VLModel now take hybrid_stack_spec and
    hybrid_layer_pattern instead of a transformer_layer_spec and an
    mtp_block_spec. get_qwen35_vl_language_spec is removed.
  • Each historical Qwen block becomes two hybrid layers: a GatedDeltaNet (G)
    or full-attention (*) layer followed by a dense (-) or MoE (E) MLP
    layer. Three GDN blocks then one attention block reproduces the
    --linear-attention-freq 4 cadence exactly.
  • MTP depths replicate the last block, matching get_gpt_mtp_block_spec, which
    derived the MTP spec from the final decoder layer.
  • Variant configs are converted from block counts to hybrid layer counts,
    because HybridModel counts one layer per pattern symbol.

mRoPE support in HybridModel (megatron/core/models/hybrid/hybrid_model.py)

  • Build a MultimodalRotaryEmbedding when position_embedding_type == 'mrope'
    and compute sectioned (optionally raw, fused-kernel) freqs in forward,
    mirroring GPTModel line for line, including the
    apply_rope_fusion / rotary_interleaved / fused_single_qkv_rope /
    inference conditions and the flash-decode NotImplementedError.
  • Widen the HybridModelConfig.position_embedding_type literal accordingly.

GatedDeltaNet (megatron/core/ssm/gated_delta_net.py)

  • Import fla.ops.cp.build_cp_context separately from the rest of FLA so an FLA
    build without the CP extension still enables GatedDeltaNet, and raise a
    descriptive error only when chunkwise CP is actually requested.

Launcher (scripts/run_qwen35_vl.sh)

  • Derive the pattern from NUM_LAYERS, NUM_EXPERTS and the new
    MTP_NUM_LAYERS knob; pass the MTP arguments only when MTP is enabled.
  • NUM_LAYERS need not be a multiple of 4: trailing blocks stay GatedDeltaNet,
    which is what --linear-attention-freq 4 produced, so shallow proxy runs keep
    working.

Tests

  • examples/multimodal_dev/tests/test_hybrid_migration.py — factory wiring plus
    structural equivalence between the hybrid pattern and the former GPT layout.
    The key check cross-validates validate_segment_layers (hybrid) against
    get_linear_attention_pattern (GPT) so a semantic drift on either side fails.
  • tests/unit_tests/models/test_hybrid_model.pyHybridModel constructor with
    position_embedding_type='mrope'.
  • examples/multimodal_dev/tests/test_cp_thd_correctness.py — ported to the
    hybrid stack spec.

Checkpoint compatibility

The decoder checkpoint layout changes: one GPT decoder layer is split across two
hybrid layer indices, the final-norm key changes, and hybrid MTP uses a nested
HybridStack. An existing GPTModel-format Qwen3.5-VL checkpoint is therefore not
directly loadable. tools/checkpoint/gpt_hybrid_conversion.py does not cover
this case either — it explicitly rejects GDN (G) and MTP checkpoints. This is
documented in examples/multimodal_dev/README.md.

Scope of risk

The megatron/core changes are additive: the mRoPE branches only run when
position_embedding_type == 'mrope', which no existing HybridModel
configuration uses, and the FLA import change only alters behavior on builds
that lack fla.ops.cp. Everything else is confined to examples/multimodal_dev.

The GPTModel code path is being deprecated, so move the examples/multimodal_dev
Qwen3.5-VL language decoder from GPTModel to HybridModel.

- MultimodalModel / Qwen35VLModel now take a hybrid stack spec plus a unified
  --hybrid-layer-pattern instead of a transformer layer spec and an MTP block
  spec. Each historical Qwen block becomes two hybrid layers: a GatedDeltaNet
  ('G') or full-attention ('*') layer followed by a dense ('-') or MoE ('E')
  MLP layer, reproducing the --linear-attention-freq 4 cadence of the GPT path.
  MTP depths replicate the last block, as get_gpt_mtp_block_spec derived the
  MTP spec from the final decoder layer.
- Add mrope support to HybridModel, mirroring GPTModel: build a
  MultimodalRotaryEmbedding when position_embedding_type is 'mrope', and
  compute the sectioned (optionally raw, fused-kernel) freqs in forward.
  Widen the HybridModelConfig position_embedding_type literal accordingly.
- Because HybridModel counts one layer per pattern symbol, the Qwen variant
  configs are converted from block counts to hybrid layer counts.
- Import fla.ops.cp.build_cp_context separately from the rest of FLA so that a
  build without the CP extension still enables GatedDeltaNet, and raise a
  descriptive error only when chunkwise CP is actually requested.
- run_qwen35_vl.sh derives the pattern from NUM_LAYERS, NUM_EXPERTS and the new
  MTP_NUM_LAYERS knob, and only passes the MTP arguments when MTP is enabled.

The decoder checkpoint layout changes with this migration; see the README for
details on why existing GPTModel-format Qwen3.5-VL checkpoints are not directly
loadable.

Signed-off-by: Li Tao <lit@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant