Skip to content

[Do not merge into Main] feat(draft): add bounded multi-pass Eagle TTT - #3725

Open
seonjinn wants to merge 50 commits into
NVIDIA-NeMo:mainfrom
seonjinn:seonjinn/draft-cotrain-eagle-ttt-v4-20260819
Open

seonjinn wants to merge 50 commits into
NVIDIA-NeMo:mainfrom
seonjinn:seonjinn/draft-cotrain-eagle-ttt-v4-20260819

Conversation

@seonjinn

@seonjinn seonjinn commented Aug 20, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Adds a bounded multi-pass EAGLE-3 TTT provider.
  • Uses structured MCore attention without retaining dense pass logits or sequence-square masks.
  • Validates rotary-position support when the session is created.

Scope

Covers the provider, pass state, attention, loss, and split-step training primitives. Higher-level configuration and recipes remain out of scope.

Validation

  • Exact head: fdf2a971be0b396ed7282a9a99c79a6af24a5e7b
  • Ruff and Pyrefly pass.
  • Focused CPU suites: 50 passed / 11 CUDA-skipped; TP suite: 2 passed / 1 CUDA-skipped.
  • All completed GitHub checks pass.

Prior GPU evidence

  • Prior 4×GB200 focused suite: 139 passed with 1 optional-dependency skip.

Dependencies / Remaining

Depends on #3703 and #3706. CUDA memory cases remain GPU-only validation.

Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
@seonjinn
seonjinn requested review from a team as code owners August 20, 2026 07:56
@seonjinn seonjinn added the CI:L2 Run doctests, unit tests, functional tests, and convergence tests label Aug 20, 2026
@copy-pr-bot

copy-pr-bot Bot commented Aug 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.

@seonjinn

Copy link
Copy Markdown
Contributor Author

/review-pr-team

@seonjinn seonjinn left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Self-review before requesting reviewers.

Method: six review agents over the PR8a-only diff (8 files vs the #3703+#3706 base), then an adversarial pass that re-verified citations, ran two empirical checks on CPU torch, and re-checked CI/PR state live.

The core math held up well under adversarial verification: the multi-pass staircase visibility and the RoPE-relative shift alignment in _merge_branch were re-derived against an independently written rotate-half oracle and match to machine precision (4.4e-16, fp64); label alignment (teacher_offset = pass_index + 1) was re-worked by hand; the cross-pass detach asymmetry is pinned by an explicit test; and the TP/SP integration follows the clean pattern -- EagleTTTCoreAttention owns zero parameters, so the sharded-checkpoint bug classes from earlier PRs in this series are structurally inapplicable. The SP test (real NCCL SelfAttention with sequence_parallel=True, output + input grads + parameter grads vs a global dense oracle) is the strongest distributed test in the series so far.

The one substantive finding is the activation-recompute incompatibility (inline, empirically reproduced): with recompute_granularity=full or selective, backward re-enters the armed forward and crashes on step 1.

Process, before merge:

  1. No /ok to test has ever been issued on this PR -- zero substantive CI on any commit. Needs a fresh /ok to test 292e29d31a6276c0e4823c37d94f7c6e917f2fc1 (after the rebase below, on the new head).
  2. Rebase required: both stacked dependencies have diverged (not just advanced) -- #3706's head (40badeea) and #3703's head (5133c28d) no longer contain this PR's base 660ee3c6, so the rebase may not be clean.
  3. Body accuracy: the Ruff/pyrefly/4xGB200 numbers are self-reported (no check-runs exist); "139 passed" spans the full 13-file stacked suite, not this PR's 5 test files (~91 collected) -- worth stating the basis.
  4. Below inline threshold: MCoreEagleTTTSession is never driven past pass_count=2 off-GPU, and the "pinned_modelopt" test name pins an internal formula, not an external ModelOpt oracle -- consider a rename or a small modelopt-driven geometry diff test later.

Comment thread nemo_rl/models/megatron/draft/eagle_ttt.py
Comment thread nemo_rl/models/megatron/draft/eagle_ttt.py Outdated
Comment thread nemo_rl/models/megatron/draft/eagle_ttt.py Outdated
Comment thread nemo_rl/models/megatron/draft/eagle_ttt.py Outdated
Comment thread tests/unit/distributed/test_eagle_ttt_sp.py
Comment thread tests/unit/models/megatron/test_eagle_ttt_attention.py Outdated
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
…erge

Signed-off-by: seonjinn <sna@nvidia.com>
The FP32 vocab tile size was a constructor default that no config path
could reach, even though it is what bounds the activation footprint this
PR exists to cap. Thread it from policy.draft.token_chunk_size through
DraftLossWrapper into DraftCrossEntropyLossFn, declare it on
DraftCrossEntropyLossConfig and DraftConfig, and document the default in
the exemplar config.

Also drop the unused ctx.tp_group assignment: backward rebuilds both
distributions from the already TP-reduced log-normalizers and never
communicates.

Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
…erge

Signed-off-by: seonjinn <sna@nvidia.com>

# Conflicts:
#	pyrefly.toml
…erge

Signed-off-by: seonjinn <sna@nvidia.com>

# Conflicts:
#	nemo_rl/models/megatron/train.py
#	nemo_rl/models/policy/workers/megatron_policy_worker.py
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>

# Conflicts:
#	nemo_rl/algorithms/loss/draft.py
#	nemo_rl/algorithms/loss/loss_functions.py
#	nemo_rl/models/megatron/train.py
#	tests/unit/algorithms/test_draft_loss_wrapper.py
#	tests/unit/algorithms/test_draft_soft_ce.py
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
@seonjinn

Copy link
Copy Markdown
Contributor Author

/ok to test 95e639b

Signed-off-by: seonjinn <sna@nvidia.com>
…-main-merge

Signed-off-by: seonjinn <sna@nvidia.com>

# Conflicts:
#	nemo_rl/models/policy/__init__.py
#	pyrefly.toml
@seonjinn

Copy link
Copy Markdown
Contributor Author

/ok to test be80ab6

@seonjinn

Copy link
Copy Markdown
Contributor Author

Merged latest main (b03da0f469) and re-fired CI on be80ab656b.

main now carries the typed speculator contract from #3701, so this branch had to be adapted rather than merged verbatim. Three changes, one of which git merged clean but broke at runtime:

1. nemo_rl/models/policy/__init__.py — took main's deletion.
#3701 removed the DraftConfig / DraftConfigDisabled TypedDicts and replaced them with Eagle3DraftConfig(BaseModel, extra="allow") in nemo_rl/models/policy/draft_config.py. This branch's only addition to that file was the token_chunk_size: NotRequired[int] field, so the whole conflicted block is dropped in favour of the new contract. policy.draft.token_chunk_size still validates and still reaches the loss wrapper, as a pydantic extra.

2. pyrefly.toml — sorted union.
Both sides inserted into the same sorted list under nemo_rl/models/megatron/draft/: eagle_provider.py / eagle_ttt.py / step_state.py from here, training.py / utils.py from main.

3. nemo_rl/models/megatron/train.py — .get() no longer exists on the draft config.
This one is worth calling out because it was not a merge conflict. policy_cfg["draft"] used to be a TypedDict; after #3701 it is a pydantic model. Two sites here still read

self.cfg["draft"].get("token_chunk_size", DEFAULT_DRAFT_TOKEN_CHUNK_SIZE)

which git merged clean, passes lint, and raises AttributeError only on a draft-enabled run. Rewritten as getattr(self.cfg["draft"], "token_chunk_size", DEFAULT_DRAFT_TOKEN_CHUNK_SIZE), which preserves the exact prior semantics.

Known gap, deliberately not fixed here. token_chunk_size is left undeclared on Eagle3DraftConfig, so #3701's _reject_near_miss_extra_keys validator cannot catch a typo of it - token_chunk_sze would silently fall back to 4096 instead of raising. Declaring the field properly would mean importing DEFAULT_DRAFT_TOKEN_CHUNK_SIZE from nemo_rl/algorithms/loss/draft.py, which pulls torch into draft_config.py - a module #3701 deliberately kept to pydantic and stdlib only. Happy to declare it with a literal default here instead if reviewers prefer the typo protection over the duplicated constant.

@seonjinn seonjinn changed the title feat(draft): add bounded multi-pass Eagle TTT [Do not merge into Main] feat(draft): add bounded multi-pass Eagle TTT Sep 16, 2026
@seonjinn seonjinn added CI:L1 Run doctests, unit tests, and functional tests CI:Lfast Runs a fast test suite and re-use nightly `main` container (but sync dependencies to PRs version) and removed CI:L2 Run doctests, unit tests, functional tests, and convergence tests CI:L1 Run doctests, unit tests, and functional tests labels Sep 17, 2026

This branch has not been deployed

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

Labels

CI:Lfast Runs a fast test suite and re-use nightly `main` container (but sync dependencies to PRs version)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant