Skip to content

fix(models): resolve verifier_norm class by verifier family - #1090

Open
minziyu wants to merge 1 commit into
vllm-project:mainfrom
minziyu:fix/qwen35-verifier-norm-class
Open

fix(models): resolve verifier_norm class by verifier family#1090
minziyu wants to merge 1 commit into
vllm-project:mainfrom
minziyu:fix/qwen35-verifier-norm-class

Conversation

@minziyu

@minziyu minziyu commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Some verifier families store the final RMSNorm weight in the Gemma convention — applied gain is (1 + w) — while verifier_norm was always constructed as a plain Qwen3RMSNorm (gain w). This includes the Gemma models (as covered for Gemma3 by #892) and the Qwen3.5/Qwen3.8 family, whose Qwen3_5RMSNorm is an alias of vLLM's GemmaRMSNorm (vllm/model_executor/models/qwen3_5.py); transformers' Qwen3_5RMSNorm.forward likewise computes output * (1.0 + weight).

The mismatch silently mis-scales the reconstructed verifier targets: on a Qwen3.8-27B verifier (V=248320), feeding real model.norm.weight and real lm_head rows through both variants gives rel-L2 0.51 vs the verifier's own final hidden state (KL ~0.48 nat on the reconstructed target distribution, top-1 prob 0.008 vs 0.071 true). Training converges regardless — argmax mostly survives the ~2x scale error — so nothing flags it. Likely (part of) what #797 observed as "DFlash performs worse on Qwen3.5 than Qwen3".

Generalizes #892's Gemma3 norm-class selection into a shared resolve_verifier_norm_class helper: detection keys off the verifier's model_type / text_config.model_type (read from its config.json when resolvable) with an architectures fallback — not weight statistics, since in the Qwen3.8 checkpoint per-layer norm weights sit near zero (gemma-style storage) while the final norm weight sits near 1.0, so value-based heuristics would misfire on exactly the layer that matters. The checkpoint weight loads verbatim; the convention is applied in the norm class's forward, matching the verifier's own numerics.

Verified end-to-end on the DSpark-on-Qwen3.8 pipeline (hidden-states extraction through serving) with the equivalent weight-fold variant of this fix; a unit test asserts Gemma3RMSNorm(w) == Qwen3RMSNorm(w+1).

Refs #892, #797.

Some verifier families store the final RMSNorm weight in the Gemma
convention — applied gain is (1 + w) — while verifier_norm was always
constructed as a plain Qwen3RMSNorm (gain w). This includes the Gemma
models (as covered for Gemma3 by vllm-project#892) and the Qwen3.5/Qwen3.8 family,
whose Qwen3_5RMSNorm is an alias of vLLM's GemmaRMSNorm
(vllm/model_executor/models/qwen3_5.py); transformers'
Qwen3_5RMSNorm.forward likewise computes output * (1.0 + weight).

The mismatch silently mis-scales the reconstructed verifier targets:
on a Qwen3.8-27B verifier (V=248320), feeding real model.norm.weight
and real lm_head rows through both variants gives rel-L2 0.51 vs the
verifier's own final hidden state (KL ~0.48 nat on the reconstructed
target distribution, top-1 prob 0.008 vs 0.071 true). Training
converges regardless — argmax mostly survives the ~2x scale error —
so nothing flags it. Likely (part of) what vllm-project#797 observed as "DFlash
performs worse on Qwen3.5 than Qwen3".

Generalizes vllm-project#892's Gemma3 norm-class selection into a shared
resolve_verifier_norm_class helper: detection keys off the verifier's
model_type / text_config.model_type (read from its config.json when
resolvable) with an architectures fallback — not weight statistics,
since in the Qwen3.8 checkpoint per-layer norm weights sit near zero
(gemma-style storage) while the final norm weight sits near 1.0, so
value-based heuristics would misfire on exactly the layer that
matters. The checkpoint weight loads verbatim; the convention is
applied in the norm class's forward, matching the verifier's own
numerics.

Verified end-to-end on the DSpark-on-Qwen3.8 pipeline (hidden-states
extraction through serving) with the equivalent weight-fold variant
of this fix; a unit test asserts Gemma3RMSNorm(w) == Qwen3RMSNorm(w+1).

Refs vllm-project#892, vllm-project#797.

Signed-off-by: minziyu <645657703@qq.com>
@mergify

mergify Bot commented Sep 7, 2026

Copy link
Copy Markdown

Merge Protections

🔴 1 of 1 protections blocking · waiting on 👀 reviews

Protection Waiting on
🔴 Require approval from approved reviewers list 👀 reviews

🔴 Require approval from approved reviewers list

Waiting for any of

  • approved-reviews-by = dsikka
  • approved-reviews-by = fynnsu
  • approved-reviews-by = orestis-z
  • approved-reviews-by = rahul-tuli
  • approved-reviews-by = shanjiaz
This rule is failing.

All pull requests must have at least one approving review from a member of the approved reviewers list before merging.

  • any of:
    • approved-reviews-by = dsikka
    • approved-reviews-by = fynnsu
    • approved-reviews-by = orestis-z
    • approved-reviews-by = rahul-tuli
    • approved-reviews-by = shanjiaz

@coderabbitai

coderabbitai Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: f3ae8f4b-ecb9-4366-932a-30db599adbfb

📥 Commits

Reviewing files that changed from the base of the PR and between 3419401 and 21bdc0a.

📒 Files selected for processing (3)
  • src/speculators/models/dflash/core.py
  • src/speculators/models/utils.py
  • tests/unit/models/test_verifier_norm_convention.py

Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review.


📝 Walkthrough

Walkthrough

Changes

The PR detects the verifier’s final RMSNorm convention from model metadata. DFlash now selects the matching norm class. Tests cover metadata detection, model construction, checkpoint loading, and numerical equivalence.

Verifier Norm Convention

Layer / File(s) Summary
Verifier convention detection and class resolution
src/speculators/models/utils.py, tests/unit/models/test_verifier_norm_convention.py
The utilities detect Gemma-style conventions from verifier configuration metadata and resolve Gemma3RMSNorm or Qwen3RMSNorm. Tests cover direct, nested, fallback, and negative cases.
DFlash norm wiring and validation
src/speculators/models/dflash/core.py, tests/unit/models/test_verifier_norm_convention.py
DFlashDraftModel constructs verifier_norm with the resolved class. Tests cover default construction, raw checkpoint weights, and numerical equivalence with folded Qwen3 weights.

Merge Risk: ⚪ Minimal · up to 21bdc

DFlash now applies the verifier family’s RMSNorm gain convention while retaining checkpoint weights unchanged. The supported model-family paths and numerical behavior are covered, with no remaining current-head merge risk identified.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.56% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly explains the verifier norm mismatch, the family-based class resolution, and the validation performed.
Title check ✅ Passed The title clearly and concisely describes the main change: selecting the verifier_norm class by verifier family.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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