refactor(engine): training Engine API - #3614
Draft
HuiyingLi wants to merge 87 commits into
Draft
Conversation
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
…orward-backward # Conflicts: # nemo_automodel/recipes/llm/train_ft.py # nemo_automodel/recipes/vlm/finetune.py # tests/unit_tests/recipes/test_finetune_vlm_helpers.py # tests/unit_tests/recipes/test_train_ft.py Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
…orward-backward Signed-off-by: HuiyingLi <willwin.lee@gmail.com> # Conflicts: # nemo_automodel/components/distributed/pipelining/autopipeline.py # nemo_automodel/recipes/llm/train_ft.py # nemo_automodel/recipes/vlm/finetune.py
HuiyingLi
force-pushed
the
huiyingl/feat/datum-forward-backward
branch
from
August 21, 2026 18:54
a238fa5 to
645e5ae
Compare
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Expose CP-prepared loss side channels to eager batch contexts for model-scoped router replay. Remove the unused whole-batch AutoPipeline step API and planned multi-call accumulation, making one forward_backward call the complete optimizer window while retaining single-window lifecycle safety. Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
…orward-backward Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Molt owns the critic value head again, installed after the FSDP wrap as a plain replicated module with trainer-side DP grad sync — the pre-integration design. Reverts the pre_fsdp_hook plumbing (auto_model, infrastructure), the task-head registry (shared/task_heads.py), its TP-plan exclusion (parallelizers), FSDP-unit management and replica sync (infrastructure, fsdp_mixin), the branch-added base-load scrubbing (checkpointing), and their tests. Main's generic skip_task_head_prefixes checkpoint filtering is upstream code and stays. Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
torch's pipeline schedules already detect the eval-to-train has_backward switch and rebuild the forward receive buffers with the correct requires_grad; a 2-rank GPipe and 1F1B eval-then-step run trains fine without this shim, and its unit test only exercised a fake schedule. Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
The microbatch_size/input_tensor parameters and the first_stage_input_meta threading were added for the old engine-driven PP path; after the DeepSpeed-style rewrite no caller passes them — every recipe still calls update_seq_len(seq_len), packed THD keeps using the recipe-level pp_microbatch_size=1 override, and the VLM embeds first stage sets stage.inputs_meta directly. Restores main's single-parameter form. Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
…s THD path Restore main's versions of thd_utils, context_parallel utils/sharder, and the generic HF pipeline forward. This removes the single-packed-row width splitting (split_final_thd_batch and the batch_size==1 branch), the stack_thd_chunks helper, per-chunk ShardLayout.chunk_layouts/chunk_index verbs, and the generic-HF THD pipeline-stage branch — all built for the old engine-driven flow and without production callers on this branch. Row-group chunking for SFT+PP THD is unchanged (it is main's own path). Validated on 8xH100: DSV4 PP2 and EP2 parity, CP and TP+CP dense-packed THD functional tests, the 2-rank CP sharder token-verb test, 1590 distributed/ model unit tests, and molt's full unit suite against the reverted files. Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
vocab_parallel_log_probs/entropy aliases only ever existed between two commits on this branch; validation was written three times (public dense paths + the DTensor helper); the empty-batch gradient trick ran after a loop that never executes. Hoist validation to the public entry points, early-return the empty case, and trim private-helper docstrings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
The mixed calculate_per_token_loss error, the nn.Module/max_grad_norm constructor checks, zero_grad's module fallback, and the steps isinstance half can't trigger from any caller; _gradient_reduction_compensation had one call site. Simplify and align zero_grad's no-optimizer behavior with backward/step. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Model-parts input, the per-device topology cache, the async route validation, and per-call flag save/restore have no caller outside their own tests (molt binds one module and rollout routes are recorded, never hand-built). Also drop muse-glimmer's never-filled _thd_local_indices placeholder and a dead test mock left by the offload revert. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Two models carried the same pop/squeeze/re-add workaround because the helper squeezed dim 0 of every tensor kwarg, dropping the item axis of a single-media batch. Skipping media keys in the helper deletes both copies and covers the VLM callers that never got the workaround. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
…ad contexts VLM inlined a byte-for-byte copy of the LLM recipe's _step_pipeline_optimizer; the grad_ctx no_grad wrappers are redundant (validation callers are already @torch.no_grad and Engine.forward falls through when grads are off); VLM validation goes back to calling the model part directly; benchmark uses ga_steps instead of len(batches) and collapses the duplicated engine.step() arms. The duplicated _RecipeEngineStub moves to one shared module with Engine's real backward signature. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
The datasets.vlm package re-exports had zero consumers and made every submodule import execute collate_fns' import-time monkeypatching; the magi return_local_indices=False arms had no production caller; the media-token helpers move back beside their only caller in datasets.py; pp_media's list branch validated states no producer can create. Unify the qwen3 passthrough adapter signature with llama/qwen2. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
…tion Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
The embed-input-meta, non-first-stage sunk-model, and validation CP-reduction tests guarded code that is still live; restore them from main adapted to the current recipe internals. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
The drafter log_denominator test targets a parameter that no longer exists; the partial-CUDA-graph stub predates the two-argument _run_train_optim_step call. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Open
…orward-backward Signed-off-by: HuiyingLi <willwin.lee@gmail.com> # Conflicts: # tests/functional_tests/parallelism/compare_parallel_parity.py # tests/unit_tests/moe/test_parallelizer.py
The run-loop enablement was already reverted with the Datum Engine; the remaining periphery (validation drop_last in example configs, the parity script's val_loss metric, the Gemma4 PP2 parity extension, and the enable/disable lifecycle tests) moves to a dedicated VLM PP-validation PR. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
3 tasks
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
The mixtral packed-example switch, nemotron-parse zero-loss fix, MTP THD squeeze, fsdp_mixin dedup, parallelizer test stubs, auto_model test churn, the layer2-sink reformat, and the media-token helper relocation all came from earlier engine-era commits but are not needed by the final Engine design; drop them to keep this PR reviewable. Candidates worth their own PRs: the nemotron-parse autograd fix and the MTP THD squeeze. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
3 tasks
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
A microstep that raises (e.g. OOM between forward and backward) leaves an open gradient-sync context and a nonzero microstep counter that poison every later window; callers recovering from such failures need an explicit reset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
A NaN/inf norm means the gradients themselves are non-finite; clipping with error_if_nonfinite=False then writes NaN into every weight and the run can only be recovered from a checkpoint. Drop the update with a warning instead, matching veRL's engine behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: HuiyingLi <willwin.lee@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do ?
Adds training
Engineand migrates the LLM/VLM finetune recipes onto it. The earlier Datum-based design (structured collation metadata,forward_backwardwith loss callbacks) was dropped after review; the boundary is now the same one OpenRLHF uses on DeepSpeed:Engine(nemo_automodel/engine/_engine.py, ~300 lines) wraps an already-distributed model and owns backward, gradient finalization/clipping, optimizer update, gradient clearing, and explicit gradient-accumulation windows (set_gradient_accumulation_steps). It does not know about losses, RL, packing, or collation — callers compute the loss and prepare inputs. This is the execution boundary the molt RL integration builds on (NVIDIA-NeMo/labs-molt#92 pins this branch).Changelog
nemo_automodel/engine/_engine.py: eagerforward/backward(loss)/step()/zero_grad()/get_global_grad_norm()with explicit accumulation windows.components/loss/vocab_parallel.py:token_log_probs/token_entropyunified over dense tensors and vocab-sharded DTensor logits (distributed reductions, no vocabulary gather).components/moe/router_replay.py: routing-replay adapter covering forward, activation recomputation, and backward, including pipeline-split model parts.recipes/llm/train_ft.pyandrecipes/vlm/finetune.pyto drive training throughEngine, removing duplicated backward/clip/step logic.Validation
tests/unit_tests/test_engine.py(new),loss/test_vocab_parallel.py(new),moe/test_router_replay.py(new), andmoe/test_token_dispatcher.pyequalization coverage.tests/functional_tests/moe/run_hybridep_unequal_tokens.py(2×H100, bitwise forward+backward parity for unequal/unaligned token counts); DeepSeek-V4 PP2/EP2 and CP+TP dense-packed THD parity runs match main.Before your PR is "Ready for review"
Pre checks:
Draft while full CI and reviewer feedback are pending.
Additional Information
🤖 Generated with Claude Code