Repository navigation
Conversation
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review: 3
Please check the settings in the CodeRabbit UI or the
|
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3001 +/- ##
=======================================
Coverage 79.79% 79.80%
=======================================
Files 661 661
Lines 74935 74936 +1
=======================================
+ Hits 59798 59799 +1
Misses 15137 15137
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
edd263c to
de964a6
Compare
de964a6 to
515d225
Compare
515d225 to
a35712e
Compare
…lexAttention in the DFlash2 recipe Add training.dataloader_in_order (default false) to the speculative-decoding training arguments. With dataloader workers, a rank then takes whichever batch a worker finishes first instead of waiting for its slowest outstanding sample, and DDP no longer turns one rank's slow fetch into a stall on every rank. HF Trainer forwards the flag itself only from transformers 5.15, and accelerate's DataLoaderShard forwards attribute reads, not writes, to the torch loader it wraps. EagleTrainerWithAccLog.get_train_dataloader therefore sets it on that loader. The field shares HF's name, so on 5.15+ it overrides HF's own default. Context parallelism keeps in-order delivery: accelerate gives every rank of a CP group the same data shard, and each loads it on its own, so out of order they would split different sequences at the same step. Measured on DFlash2 streaming training, 8 trainer nodes x 4 GPUs, DDP, global batch 64, seq 4096, 8 workers per rank, same data_seed: - in_order=False at 8 serve + 8 trainer nodes: 0.655 -> 0.523 s/step; serve replicas 26% -> 3% idle; worst per-rank batch wait 5.9 s -> ~2 s. - Over ~2.5K steps: mean |loss diff| <= 0.016, mean acceptance diff within +-0.003. Also turn on dflash_use_torch_compile and dflash_use_flex_attention in the DFlash2 recipe, the configuration the numbers below were measured with. With the trainer as the bottleneck (12 or 16 serve + 8 trainer nodes) compile gave 0.445 -> 0.386 and 0.446 -> 0.389 s/step with no recompiles over 2.5K steps; when serve-bound it gave nothing. On one GPU at the shipped online example's shape (PyTorch 2.10, tf32 off) the recipe goes from 1612 to 985 ms/step (1.64x). On PyTorch 2.9/2.10 the recipe's tf32: true makes Inductor's TF32 check raise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: h-guo18 <67671475+h-guo18@users.noreply.github.com>
|
/claude review |
ChenhanYu
left a comment
There was a problem hiding this comment.
Pensieve comment review using chenhany's profile (revision 12).
Comment: DFlash2 now enables a compile/TF32 combination documented to crash on supported PyTorch 2.10.
Needs action:
- Fix
modelopt_recipes/general/speculative_decoding/dflash2.yaml:73with compatible defaults or a version guard; extend GPU coverage to execute the shipped compile+FlexAttention configuration through forward/backward (inline). - Move the worker-based regression at
tests/unit/examples/test_speculative_decoding_main.py:344totests/gpu*, following the baseAGENTS.mdandCONTRIBUTING.mdmultiprocessing rule (inline).
No action needed:
- Loader unwrapping, argument plumbing and the CP ordering guard look consistent. The ordering regression checks actual delivery and preservation of every sample.
- Existing test edits update scope documentation and add cases without weakening assertions. The diff adds 16 core source lines; no licensing changes were identified.
- Baseline:
687720b5d17c40c9d9fd7d28cc6622d5df99cdf6. Tests were not executed; current-head CI results were unavailable. Duplicate checking covers the supplied bounded history only.
Review baseline: https://github.com/NVIDIA/Model-Optimizer/blob/687720b5d17c40c9d9fd7d28cc6622d5df99cdf6/.agents/review-guidelines/code-review.md
[blocking] modelopt_recipes/general/speculative_decoding/dflash2.yaml:73 — Enabling compilation while retaining training.tf32: true at line 61 introduces a default-path failure on PyTorch 2.10, explicitly documented in the added CHANGELOG.rst:32 and the PR's reported testing. PyTorch 2.10 remains supported (pyproject.toml:40 specifies torch>=2.10); main.py forwards these settings unchanged, and DFlashModule.compile_body unconditionally uses Inductor. Documenting an override does not preserve the previously working recipe defaults. Set a compatible TF32 default, keep compilation opt-in on affected versions, or add a compatibility guard. Extend existing GPU coverage to execute the resulting shipped compile+FlexAttention configuration through forward/backward on the supported Torch floor.
[warning] tests/unit/examples/test_speculative_decoding_main.py:356 — With dataloader_num_workers=2, this new parametrized unit test starts fresh worker processes for each case and does not use the shared cpu_dist_workers fixture. The base AGENTS.md 'Adding tests' rule and CONTRIBUTING.md:196-200 explicitly place process-starting tests in tests/gpu*, with the shared CPU fixture as the exception. The reported fork timings and non-fork skip do not satisfy that placement rule. Move the worker-driven ordering regression and its helpers to tests/gpu*; the lightweight CP argument-wiring test can remain here.
Review run: 0b09cb37cfc94ea1a6a76cb2ad251341
There was a problem hiding this comment.
The out-of-order dataloader work is clean and well tested, but the DFlash2 recipe as shipped now fails on the first step on torch 2.10 — the minimum version pyproject.toml allows.
Needs action:
- Set
tf32: falseinmodelopt_recipes/general/speculative_decoding/dflash2.yaml, or raise an actionable error from the compile path: per your own PR body,tf32: true+dflash_use_torch_compile: truemakes Inductor raise on torch 2.9/2.10, and your numbers show tf32 buys nothing here. - Add a comment beside the two newly flipped
dflash:flags naming the short-answer regression (compile pins blocks todflash_num_anchors; 3.6x slower in your toy run) anddflash.dflash_use_torch_compile=false. Today that caveat is only in the PR body. - Default
dataloader_in_ordertoTrueand set itfalsein the streaming recipes that benefit, or explain in the PR body why the repo-wide flip is preferred — the gain was measured in one mode, the determinism loss lands on all of them. - Warn via
warn_rank_0whencp_size > 1overrides an explicitdataloader_in_order=falseinmain.py:132.
No action needed:
- Two unit tests cover the flag reaching the torch loader and the CP guard; both fail without the change. 81 added lines, well under the size budget. No licensing surface.
- Baseline
.agents/review-guidelines/code-review.mdat687720b5; reviewed head1ef49638; all 6 changed files read. Stacked onhaoguo/dflash-rope-fp32, so the diff is against that base. - Verification limits: no tests or CI run, and the sandbox here blocked inspecting the installed
accelerate/transformers, so thebase_dataloaderreach-through andskip_first_batchescarry-over are assessed from source and your reported runs, not re-verified.
shengliangxu
left a comment
There was a problem hiding this comment.
Bot review (gpt-6.1-sol) — DM the bot to share feedback.
Changes requested: the DFlash2 default fails on supported PyTorch 2.10, and the documented eager opt-out is ignored on HF-checkpoint resume.
Needs action:
- Fix TF32/Inductor compatibility in
dflash2.yamland add a real GPU forward/backward test for the combined compile+FlexAttention default (inline at line 73). - Honor compile/FlexAttention overrides on HF-checkpoint resume in
main.py, preserving weights and saved ModelOpt configuration; add resume coverage (inline atCHANGELOG.rst:32). - Move the two-worker loader integration test out of
tests/unitintotests/gpu*, following CONTRIBUTING’s process-spawning-test rule (inline attest_speculative_decoding_main.py:356).
|
|
||
| - Add the **external draft** speculative-decoding mode: train a pretrained standalone draft model against a cached base model, instead of grafting a draft head onto the target. Select it with ``mtsp.convert(draft, [("external", cfg)])`` or the ``speculative_external`` recipe; the draft keeps its own embeddings and lm_head and exports as an ordinary HF checkpoint. | ||
| - With ``training.dataloader_num_workers`` > 0, ``examples/speculative_decoding/main.py`` now yields each training batch as soon as a worker finishes it, so one slow sample, such as a slow hidden-state fetch in streaming training, no longer stalls every DDP rank. Sample order within the prefetch window is then no longer deterministic; set ``training.dataloader_in_order=true`` to restore it (context-parallel runs always keep it). | ||
| - The ``general/speculative_decoding/dflash2`` recipe now enables ``dflash_use_torch_compile`` and ``dflash_use_flex_attention``. With PyTorch 2.9 or 2.10 its ``tf32: true`` makes Inductor fail on the first step; set ``training.tf32=false`` or ``dflash.dflash_use_torch_compile=false`` there. |
There was a problem hiding this comment.
Bot comment.
[P2] The dflash.dflash_use_torch_compile=false workaround does not take effect when resuming a consolidated HF checkpoint created with compilation enabled. main.train() detects checkpoints automatically and its HF-format branch restores the saved ModelOpt config through from_pretrained; only the fresh/sharded-checkpoint branch consumes recipe.dflash. Thus the restored model retains dflash_use_torch_compile=True and _compiled_body, despite the CLI override. The Usage snippet's FlexAttention opt-out is likewise ignored on that path. Please apply these execution flags to the restored model without rebuilding its draft weights, synchronize the saved ModelOpt configuration, and add an HF-resume test that switches a compile+flex checkpoint back to eager SDPA.
There was a problem hiding this comment.
That's right, but it isn't specific to these two flags. On the HF-format resume path, from_pretrained restores the whole DFlash config saved with the checkpoint, and recipe.dflash is never read, so every DFlash setting given at resume is ignored, not only compile and flex. Deciding which settings may override a checkpoint on resume, and keeping the saved config in sync, is a change to resume semantics. I'd rather do that in its own PR than inside this one.
For this PR, 4f3724e narrows the CHANGELOG entry: the override applies when a run starts, and a resumed run keeps the checkpoint's DFlash settings. The PR description's usage line now says the same.
…the worker test to examples Review follow-ups. - The recipe turns tf32 off. With dflash_use_torch_compile on, TF32 makes Inductor fail at the first step on PyTorch 2.9 and 2.10, and 2.10 is the lowest version ModelOpt supports. DFlash2 trains in bf16, so TF32 only reached fp32 matmuls such as the draft's rotary embedding. - The recipe now says, next to the compile and flex flags, that both fix the draft's block count at dflash_num_anchors, which costs more than it saves on very short answers. - A GPU test runs the recipe's compile + flex pair forward and backward on a tiny model and checks the loss against eager flex. It passes on PyTorch 2.10 and 2.13. - The dataloader ordering test starts DataLoader workers, so it moves from tests/unit to tests/examples/speculative_decoding, the lane that runs when the trainer code under examples/ changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: h-guo18 <67671475+h-guo18@users.noreply.github.com>
|
Thanks for the Pensieve review. Both items are addressed in de31718:
The Claude review's threads each have a reply. The PRs above this one in the stack are rebased onto it. |
…t; scope the eager override Review follow-ups. - test_compiled_flex_matches_eager_flex now builds the recipe's DFlash2 draft (conv projector and candidate selector) and objective (lambda LK loss, no self-distillation), sized for the test model, instead of a plain DFlash draft. It passes on PyTorch 2.10 and 2.13. - The CHANGELOG entry says the compile/flex override applies when a run starts: a run resumed from a consolidated checkpoint restores the DFlash settings saved with it, as it already did for every DFlash setting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: h-guo18 <67671475+h-guo18@users.noreply.github.com>
a35712e to
1ef4963
Compare
|
/claude review |
There was a problem hiding this comment.
Approving: the TF32/Inductor crash, the missing compile+flex GPU coverage and the tests/unit worker test are all fixed, and the 16 added logic lines hold up.
No action needed:
- ✔️ Resolved since the last review:
tf32: falsewith the Inductor reason inline, the short-answer caveat beside the flippeddflash:flags, the default-flip rationale in the PR body, and the worker test out oftests/unit. hf_dflash.py:706confirms compile or flex pins the anchor count, so the new recipe comment is accurate; the new GPU test'sdflash_use_torch_compile=Truedoes override the shared helper's eager default, andtests/examplesallows 300 s.- Only
tools/launcher/common/eagle3/train_eagle_streaming.shsetsdataloader_num_workers > 0today, so the out-of-order default changes behavior just for the streaming path it was measured on. tests/examples/speculative_decodingalready hosts process-spawning tests and its lane watchesexamples/, which meets CONTRIBUTING's intent of keepingtests/unitfast.- The
warn_rank_0idea for the CP override is still unimplemented atmain.py:133; you replied in-thread and inline threads aren't readable from this run, so I'm not re-raising it. - Baseline
.agents/review-guidelines/code-review.mdat687720b5; head4f3724ef; all 8 changed files read; the new test's header matchesLICENSE_HEADER. Limits: no tests or CI run, and the installedaccelerate/transformerswere again not inspectable, so thebase_dataloaderreach-through rests on the new ordering test and your reported runs.
ChenhanYu
left a comment
There was a problem hiding this comment.
Automatic approval delegated by chenhany (mode: approve).
Pensieve approve review using chenhany's profile (revision 12).
Approve: the prior compatibility and coverage concerns are resolved; no new material defects were found.
No action needed:
- ✔️ Resolved since
5727331218: the TF32 default, real compile+FlexAttention forward/backward coverage, and worker-test placement. The short-answer caveat and default-ordering rationale are also present. - The worker regression belongs in the example integration lane: its filter watches
examples/speculative_decoding/, unlike the GPU-test filter, and process startup is outsidetests/unit. It checks both ordering modes and preservation of every sample. - The new GPU case exercises actual Inductor compilation with DFlash2 components, compares loss against eager FlexAttention, and checks finite gradients. Existing test assertions are unchanged.
- The fresh-run opt-out documentation now explicitly excludes checkpoint resume; preserving saved DFlash settings predates this PR. The optional CP-warning suggestion has a reasonable documented rationale for omission.
- The diff adds 16 core source lines; the new test header matches
LICENSE_HEADER. - Baseline:
687720b5d17c40c9d9fd7d28cc6622d5df99cdf6. Tests were not executed; current-head CI results were unavailable. Duplicate checking covers the supplied bounded history only.
Review baseline: https://github.com/NVIDIA/Model-Optimizer/blob/687720b5d17c40c9d9fd7d28cc6622d5df99cdf6/.agents/review-guidelines/code-review.md
Review run: c9bfb4fbccad432db9e6b4dcae836cba
Stack (merge in this order; each PR's base is the branch of the one before it). [4/4] reproduces nvidia/Muse-Spark-Open-816B-A42B-DFlash2 and needs all of them.
What does this PR do?
Type of change: new feature
Two speculative-decoding training speedups.
1. Out-of-order training batches. New
training.dataloader_in_order, defaultfalse. With DataLoader workers, a rank takes whichever batch a worker finishes first instead of waiting for its slowest outstanding sample (head-of-line blocking). Per-sample fetch latency varies, and DDP lockstep turns one rank's stall into a stall on every rank.in_orderonly from transformers 5.15. accelerate'sDataLoaderShardforwards attribute reads, not writes, to the torch loader it wraps, soprepared.in_order = Falsesilently does nothing.EagleTrainerWithAccLog.get_train_dataloadertherefore sets it on the underlying loader. The field shares HF's name, so on transformers >= 5.15 it overrides HF's own default.training.dataloader_in_order=truerestores it. Nothing changes withdataloader_num_workers=0, the online-mode default.num_workers x prefetch_factorbatches per rank) changes. HF's own default from transformers 5.15 istrue, and this field deliberately overrides it.init_distributed_envsets the flag totruewhencp_size > 1.skip_first_batchesrebuilds the loader and carriesin_orderover (accelerate >= 1.3; ModelOpt requires >= 1.6). The resume position is exact only to within the batches in flight at the save, at mostnum_workers x prefetch_factorper rank.2. Compile + FlexAttention in the DFlash2 recipe:
dflash_use_torch_compileanddflash_use_flex_attentiongofalse -> trueingeneral/speculative_decoding/dflash2.yaml, the configuration the multi-node numbers below were measured with, andtf32goestrue -> false(see the first caveat).dflash,domino,dspark,lilicorr*and the launcher examples are unchanged; they are possible follow-ups.One GPU (RTX PRO 6000, PyTorch 2.10,
tf32=false), the shipped online example's shape (Qwen3-8B, seq 4096, 512 anchors, SWA 2048, bs 1), 40 steps:Measured on DFlash2 streaming training. A large MoE target is served by vLLM replicas (TP4/EP4), and the trainer pulls hidden states over RDMA. 8 trainer nodes x 4 GB300, DDP, global batch 64, seq 4096, 8 workers per rank, same
data_seedthroughout. These numbers come from a fork of this repo, not frommain:in_order=False, 8 serve + 8 trainer nodes: 0.655 -> 0.523 s/step (+25%). Serve replicas went from 26% idle to 3%, and the worst per-rank batch wait from 5.9 s to ~2 s.dflash_use_flex_attentionon, as this recipe now does, with DDP and bf16.Compile caveats, found while testing this PR:
tf32on, Inductor raises on the first step ("mix of the legacy and new APIs to set the TF32 status"). transformers enables TF32 throughtorch.backends.fp32_precision, and Inductor 2.9/2.10 then reads the legacyallow_tf32flag, which raises. Inductor reads it whenever the compiled graph has an fp32 CUDA matmul, and the draft's rotary embedding is one. PyTorch 2.8 and >= 2.11 are fine. PyTorch 2.10 is ModelOpt's floor, so the recipe now turnstf32off. DFlash2 trains in bf16, so TF32 only reached fp32 matmuls such as that one.dflash_num_anchors, while eager sizes it to the batch. With short answers the padding costs more than compile saves: in a toy run with ~35-token answers at seq 512, steps were 3.6x slower._get_attn_fncaches the attention function on the module inside the compiled region.Usage
Testing
tests/examples/speculative_decoding/test_dataloader_in_order.py::test_dataloader_in_order_reaches_the_torch_loader[False/True]tests/unit.test_context_parallelism_keeps_batches_in_order[1/2]:init_distributed_envforces in-order delivery forcp_size=2only. Thecp_size=2case fails without the guard.tests/gpu/torch/speculative/plugins/test_hf_dflash.py::TestDFlashFlexAttentionGPU::test_compiled_flex_matches_eager_flex: the recipe's compile + flex pair runs forward and backward on a tiny model with the recipe's DFlash2 draft (conv projector, candidate selector) and objective, with the loss within bf16 tolerance of eager flex and finite grads. It passes on PyTorch 2.10, the floor, and on 2.13 (about 15 s, mostly compilation).Before your PR is "Ready for review"
Make sure you read and follow Contributor guidelines and your commits are signed (
git commit -s -S).Make sure you read and follow the Security Best Practices (e.g. avoiding hardcoded
trust_remote_code=True,torch.load(..., weights_only=False),pickle, etc.).training.dataloader_in_order=truerestores it), and the DFlash2 recipe now compiles, uses FlexAttention and turns TF32 off.CONTRIBUTING.md: N/AAdditional Information
🤖 Generated with Claude Code