feat(eagle3): add per-layer FC normalization (--fc-norm) - #670
Conversation
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
The quality checks have failed. Please run |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
tests/integration/models/test_model_forward.py (1)
385-408: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winAssert the checkpoint key contract for
fc_norm.The PR objective depends on vLLM-compatible parameter names; add a direct
state_dictassertion so this test catches accidental key drift.✅ Proposed test hardening
assert model.fc_norm is not None assert len(model.fc_norm) == 3 + assert all(f"fc_norm.{idx}.weight" in model.state_dict() for idx in range(3)) assert model.input_norm is None @@ assert model.fc_norm is not None assert len(model.fc_norm) == 3 + assert all(f"fc_norm.{idx}.weight" in model.state_dict() for idx in range(3)) samples = _make_samples([128])As per path instructions, tests should cover new code paths introduced in the PR.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/integration/models/test_model_forward.py` around lines 385 - 408, The fc_norm tests only validate runtime behavior and miss the parameter-name contract required for vLLM compatibility. Update test_fc_norm and/or test_peagle_fc_norm to assert the model.state_dict contains the expected fc_norm checkpoint key(s) for the fc_norm path, using make_eagle3_model, make_peagle_model, and fc_norm to locate the affected code. Keep the existing shape/loss checks, but add a direct state_dict key assertion so accidental key drift is caught when new code paths are introduced.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/cli/train.md`:
- Around line 139-141: The CLI docs for the train flags are missing the
llama-specific default for `--norm-output`, so the current description still
implies it is always `False`. Update the flag documentation near `--fc-norm` to
explicitly note that `scripts/train.py` applies the same `is_llama_eagle`
conditional defaulting to `--norm-output`, and make sure the wording matches the
current behavior for llama vs non-llama runs. Use the existing flag descriptions
in this section as the reference point and keep the defaults consistent with the
implementation.
In `@scripts/train.py`:
- Around line 1037-1049: Update the help text for the argparse options in
train.py so it matches the real defaulting logic: both --fc-norm and
--norm-output are only implicitly true when the draft architecture condition is
satisfied together with --speculator-type being eagle3 or peagle, not for llama
draft arch alone. Adjust the help strings near the parser.add_argument calls for
these flags to reflect the combined condition used elsewhere in the argument
parsing logic.
In `@src/speculators/convert/eagle/eagle3_converter.py`:
- Line 43: The fc_norm handling in Eagle3 conversion is treating an explicit
False the same as “not provided,” so the caller cannot override a checkpoint’s
truthy value. Update the config merge logic in the Eagle3 converter’s conversion
path (the code that builds the speculator config from eagle_config and the
fc_norm parameter) to distinguish None/default from an explicit boolean, so
fc_norm=False is written through instead of falling back to the checkpoint
value. Apply the same fix anywhere the converted config is assembled from legacy
checkpoint settings in this converter.
In `@src/speculators/models/eagle3/core.py`:
- Around line 104-115: Reject invalid Eagle 3 configs by validating the
normalization flags in the model setup: in Eagle3 core initialization, ensure
`config.fc_norm` cannot be enabled at the same time as
`norm_before_fc`/`input_norm` creation, since that would make `forward` apply
both normalization paths. Add a config check near the `self.fc_norm` /
`self.input_norm` setup in `src/speculators/models/eagle3/core.py` and raise a
clear error when both FC normalization modes are requested, so only one
documented Eagle 3.1 path is allowed.
---
Nitpick comments:
In `@tests/integration/models/test_model_forward.py`:
- Around line 385-408: The fc_norm tests only validate runtime behavior and miss
the parameter-name contract required for vLLM compatibility. Update test_fc_norm
and/or test_peagle_fc_norm to assert the model.state_dict contains the expected
fc_norm checkpoint key(s) for the fc_norm path, using make_eagle3_model,
make_peagle_model, and fc_norm to locate the affected code. Keep the existing
shape/loss checks, but add a direct state_dict key assertion so accidental key
drift is caught when new code paths are introduced.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: f48a6149-82b5-47f7-b673-4178bb64cd9c
📒 Files selected for processing (9)
docs/cli/train.mdscripts/train.pysrc/speculators/convert/eagle/eagle3_converter.pysrc/speculators/models/eagle3/config.pysrc/speculators/models/eagle3/core.pysrc/speculators/models/peagle/core.pytests/integration/conftest.pytests/integration/models/test_model_forward.pytests/unit/test_config.py
|
This pull request has merge conflicts that must be resolved before it can be |
Add fc_norm: per-layer RMSNorm on each auxiliary hidden state before concatenation and FC projection — concat(Norm(h_a), Norm(h_b), Norm(h_c)) — matching the Eagle 3.1 paper specification. This differs from norm_before_fc which applies a single norm to the full concatenation. Defaults to True for llama draft arch (along with norm_output). norm_before_fc no longer defaults to True for llama arch since fc_norm is the more principled alternative. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Orestis Zambounis <orestis.zambounis@gmail.com>
The vLLM model uses `self.fc_norm` (singular) for the ModuleList, producing weight names like `fc_norm.0.weight`. Align the speculators attribute name so checkpoints are directly loadable without remapping. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Orestis Zambounis <orestis.zambounis@gmail.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Orestis Zambounis <orestis.zambounis@gmail.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Orestis Zambounis <orestis.zambounis@gmail.com>
The two flags apply conflicting normalization strategies to the FC input — using both causes double-norming. Add a Pydantic model validator to raise early with a clear error message. Signed-off-by: Orestis Zambounis <orestis.zambounis@neuralmagic.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Orestis Zambounis <orestis.zambounis@gmail.com>
Fixes mypy error: assigning None to a variable inferred as ModuleList. Signed-off-by: Orestis Zambounis <orestis.zambounis@neuralmagic.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Orestis Zambounis <orestis.zambounis@gmail.com>
Signed-off-by: Orestis Zambounis <orestis.zambounis@neuralmagic.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Orestis Zambounis <orestis.zambounis@gmail.com>
shanjiaz
left a comment
There was a problem hiding this comment.
Looks good just one small non-blocking concern
Replace hardcoded `3` with `len(eagle_aux_hidden_state_layer_ids)` for the FC layer input dim, input_norm dim, fc_norm ModuleList count, and peagle mask_hidden param so users can experiment with different numbers of auxiliary hidden state layers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Orestis Zambounis <orestis.zambounis@gmail.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Orestis Zambounis <orestis.zambounis@gmail.com>
|
This pull request has merge conflicts that must be resolved before it can be |
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Orestis Zambounis <orestis.zambounis@gmail.com>
…t#670) ## Summary - Add `--fc-norm` flag for per-layer RMSNorm on each auxiliary hidden state before concatenation and FC projection: `concat(Norm(h_a), Norm(h_b), Norm(h_c))` - This matches the Eagle 3.1 paper specification and vLLM's `fc_norm` config field - Differs from `--norm-before-fc` which applies a single norm to the full concatenation: `Norm(concat(h_a, h_b, h_c))` - `norm_before_fc` and `fc_norm` are validated as mutually exclusive in the config (enabling both would cause double-norming) ## Test plan ```bash pytest tests/unit/test_config.py -k "fc_norm" -v pytest tests/integration/models/test_model_forward.py -k "fc_norm" -v ``` - `test_fc_norm` — Eagle3 with fc_norm + norm_output, verifies fc_norms module created and forward + backward pass - `test_peagle_fc_norm` — P-Eagle with fc_norm - `test_eagle3_config_fc_norm_roundtrip` — config serialization roundtrip - `test_eagle3_config_rejects_both_norm_before_fc_and_fc_norm` — mutual exclusivity validation 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: Orestis Zambounis <orestis.zambounis@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…t#670) ## Summary - Add `--fc-norm` flag for per-layer RMSNorm on each auxiliary hidden state before concatenation and FC projection: `concat(Norm(h_a), Norm(h_b), Norm(h_c))` - This matches the Eagle 3.1 paper specification and vLLM's `fc_norm` config field - Differs from `--norm-before-fc` which applies a single norm to the full concatenation: `Norm(concat(h_a, h_b, h_c))` - `norm_before_fc` and `fc_norm` are validated as mutually exclusive in the config (enabling both would cause double-norming) ## Test plan ```bash pytest tests/unit/test_config.py -k "fc_norm" -v pytest tests/integration/models/test_model_forward.py -k "fc_norm" -v ``` - `test_fc_norm` — Eagle3 with fc_norm + norm_output, verifies fc_norms module created and forward + backward pass - `test_peagle_fc_norm` — P-Eagle with fc_norm - `test_eagle3_config_fc_norm_roundtrip` — config serialization roundtrip - `test_eagle3_config_rejects_both_norm_before_fc_and_fc_norm` — mutual exclusivity validation 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: Orestis Zambounis <orestis.zambounis@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Eros483 <arnabmandal2912@gmail.com>
Summary
--fc-normflag for per-layer RMSNorm on each auxiliary hidden state before concatenation and FC projection:concat(Norm(h_a), Norm(h_b), Norm(h_c))fc_normconfig field--norm-before-fcwhich applies a single norm to the full concatenation:Norm(concat(h_a, h_b, h_c))norm_before_fcandfc_normare validated as mutually exclusive in the config (enabling both would cause double-norming)Test plan
test_fc_norm— Eagle3 with fc_norm + norm_output, verifies fc_norms module created and forward + backward passtest_peagle_fc_norm— P-Eagle with fc_normtest_eagle3_config_fc_norm_roundtrip— config serialization roundtriptest_eagle3_config_rejects_both_norm_before_fc_and_fc_norm— mutual exclusivity validation🤖 Generated with Claude Code