Skip to content

cp: feat(qwen3_5): port dense Qwen3.5 to a custom-model(2557) into r0.5.0#2663

Merged
HuiyingLi merged 1 commit into
r0.5.0from
cherry-pick-2557-r0.5.0
Jun 20, 2026
Merged

cp: feat(qwen3_5): port dense Qwen3.5 to a custom-model(2557) into r0.5.0#2663
HuiyingLi merged 1 commit into
r0.5.0from
cherry-pick-2557-r0.5.0

Conversation

@akoumpa

@akoumpa akoumpa commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Cherry-pick of #2557 (28541ee) onto r0.5.0.

Why this is on the release branch: #2557 was not originally labeled r0.5.0. It is being backported as a prerequisite for #2484 (preserve fp32 A_log in Qwen3.5-MoE / Qwen3-Next GatedDeltaNet). #2484 builds on the generalized _fp32_params holder mechanism and the native Qwen3.5 model that #2557 introduces, so it cannot be cherry-picked alone. The #2484 cherry-pick (#2664) is stacked on this branch and should merge after this one.

Release-branch resolutions

Validation (CPU/local): py_compile clean (20 files); native qwen3_5.model + optimized_tp_plans import cleanly; 267 CPU unit tests pass (full qwen3_5 suite, moe/test_parallelizer, _transformers auto_model + capabilities, cast_model_to_dtype). GPU parity not re-run locally — see #2557's own 8×H100 validation.

…tion (#2557)

* feat(qwen3_5): port dense Qwen3.5 to a native custom-model implementation

Build the dense Qwen3.5 model as a custom implementation (its own backbone
on the shared Block + CPAwareGatedDeltaNet + fp32 SSMGate built at __init__),
mirroring Qwen3.5-MoE, instead of mutating the HF model at runtime via
patch_hf_model class-swaps + an __getattr__ monkeypatch. Removes
patch_hf_model/apply_model_runtime_patches, Qwen3_5TextModelPP, and
decoder_layer.py. The native fp32 SSMGate keeps A_log/dt_bias in fp32 storage
(true master weights) under a bf16 bulk dtype via its own fp32 FSDP group.

Signed-off-by: HuiyingLi <willwin.lee@gmail.com>

* fix(qwen3_5): align dense VLM lm_head dtype and refresh stale tests

The native dense backbone is swapped in after HF's super().__init__, but HF
post_init -> init_weights -> initialize_weights already ran against the inherited
text model, casting lm_head to the bulk (bf16) dtype. Realign lm_head to the
backbone dtype after the swap so final hidden states and lm_head agree, and
guard the backbone init_weights(buffer_device=...) call against the still-HF
text model during post_init (try/except, mirroring the MoE sibling).

Refresh tests for the native-fp32-SSMGate design: dense/VLM adapters now route
both A_log and dt_bias into the _fp32_params holder; add coverage for
cast_model_to_dtype(skip_modules=...) and the MoE adapter fp32 route/strip
helpers. Pin the tiny MTP test config to fp32 to match HF parity.

Signed-off-by: HuiyingLi <willwin.lee@gmail.com>

* test(qwen3_5): cover native dense backbone and fp32 SSMGate machinery

Add CPU unit tests for the custom-model building blocks that replaced the old
runtime patch_hf_model: SSMGate / install_ssm_gate / the _SSMGateParam descriptor
(fp32 param relocation + attribute resolution), _resolve_ssm_dtype,
Fp32SafeQwen3_5TextRotaryEmbedding (fp32 inv_freq survives a bf16 cast), and
Qwen3_5DenseTextBackbone forward-shape smoke tests (full/linear/mixed layer
types, inputs_embeds, KV-cache guard). Addresses the review's coverage gap for
the new native implementation.

Signed-off-by: HuiyingLi <willwin.lee@gmail.com>

* style(qwen3_5): apply ruff format to cp_linear_attn and moe parallelizer

CI ruff format --check (ruff 0.9.10) flagged trailing blank lines and a
wrapped call that fit on one line in the dense custom-model changes. No
behavior change.

Signed-off-by: HuiyingLi <willwin.lee@gmail.com>

* fix(qwen3_5): detect layer_types hybrids so CP works with SDPA (no TE)

Qwen3.5 dense+MoE are hybrid (linear_attention gated-delta + full_attention)
but were not detected as hybrid because their config exposes the structure via
per-layer ``layer_types`` rather than ``layers_block_type`` / ``is_hybrid_model``.
Without hybrid detection, ``ModelSupports.supports_cp`` took the "requires TE
attention" branch, wrongly forcing ``backend.attn=te`` for context-parallel
(cp_size>1). ``_is_hybrid`` now also returns True when a config's ``layer_types``
contains "linear_attention" and drills into a nested ``text_config`` (VLM
configs), so ``supports_cp`` allows ``attn in (te, sdpa)`` for these models and
dense CP works with SDPA again.

Verified on 8xH100 (dense 4B, fp32, medpix): cp_size=1 and cp_size=2 both train
20 steps with CP1==CP2 parity (step-0 loss diff 2e-4, max 0.034).

Signed-off-by: HuiyingLi <willwin.lee@gmail.com>

* fix(qwen3_5): guard fp32-holder sharding for non-module blocks; fix stale tests

L0_Unit_Tests_CPU surfaced two regressions from the dense custom-model port:

- _shard_fp32_param_holders unconditionally called block.named_modules(), which
  broke moe/test_parallelizer.py's plain (non-nn.Module) DummyBlock stubs. Guard
  with hasattr(block, "named_modules") and return an empty set — a block that
  cannot enumerate submodules cannot hold _fp32_params.

- test_auto_model TestModelRuntimePatches asserted Qwen3.5 runtime-patch dispatch,
  but the port emptied _MODEL_RUNTIME_PATCHES (models build their CP/fp32-gate
  modules at construction). Rewrite the dispatch/dedup tests to inject a temporary
  registry entry so they cover the mechanism without a built-in entry.

Signed-off-by: HuiyingLi <willwin.lee@gmail.com>

* fix(qwen3_5): TP/PP-robust attention reshape, AC-safe Block._mlp, native TP plan registration

- Qwen3NextAttention.forward: infer local head count via -1 in q/k/v
  reshape so colwise-sharded q/k/v_proj (TP) yield the correct per-rank
  head count instead of asserting the full (unsharded) head count.
- Block._mlp: unwrap CheckpointWrapper (_checkpoint_wrapped_module) before
  the MLP/MoE isinstance dispatch so activation checkpointing does not
  break the dense (MLP) path.
- optimized_tp_plans: register the native Qwen3_5ForConditionalGeneration
  and Qwen3_5ForCausalLM qualnames against _parallelize_qwen3_5_vlm so the
  custom dense model routes to the Qwen3.5 TP plan.

Verified: dense 4B TP2+PP4 (AC on, fp32 storage, pipeline bf16) trains;
MoE small fp32 loss unchanged (12.8736->12.8792->12.8772).

Signed-off-by: HuiyingLi <willwin.lee@gmail.com>

* test(qwen3_5): pin rope_fusion=False and run linear-attn forward on CUDA

The dense backbone + MTP unit tests built BackendConfig without setting
rope_fusion, which defaults to (HAVE_TE and torch.cuda.is_available()). That
is False on CPU dev boxes but True on the GPU CI runner, where Qwen3.5's
gated-query RoPE hits TE's fused rope kernel and fails with 'expected 4D
tensor'. Every Qwen3.5 recipe sets rope_fusion=false, so pin it in the test
backends to exercise the supported (non-fused) path deterministically.

Also make test_forward_shape_mixed_layers build the backbone + inputs on CUDA
(skipping when unavailable): the linear_attention block runs FLA's
gated-delta-rule / causal_conv1d CUDA kernels, which require CUDA tensors and
were previously masked by the earlier rope failure.

Signed-off-by: HuiyingLi <willwin.lee@gmail.com>

---------

Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
(cherry picked from commit 28541ee)
Signed-off-by: Alexandros Koumparoulis <akoumparouli@nvidia.com>
@akoumpa akoumpa requested a review from a team as a code owner June 20, 2026 02:16
@akoumpa akoumpa added Run CICD Trigger Testing CICD cherry-pick labels Jun 20, 2026
@copy-pr-bot

copy-pr-bot Bot commented Jun 20, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@akoumpa akoumpa requested a review from HuiyingLi June 20, 2026 02:16
@akoumpa

akoumpa commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test f312292

@akoumpa

akoumpa commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test f312292

@HuiyingLi HuiyingLi changed the title cp: feat(qwen3_5): port dense Qwen3.5 to a native custom-model implementation (2557) into r0.5.0 cp: feat(qwen3_5): port dense Qwen3.5 to a custom-model(2557) into r0.5.0 Jun 20, 2026
@HuiyingLi HuiyingLi enabled auto-merge (squash) June 20, 2026 02:44
@HuiyingLi HuiyingLi merged commit bf7f98b into r0.5.0 Jun 20, 2026
77 of 81 checks passed
@HuiyingLi HuiyingLi deleted the cherry-pick-2557-r0.5.0 branch June 20, 2026 04:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cherry-pick Run CICD Trigger Testing CICD

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants