Repository navigation
Conversation
…rics The next commit has the speculative-decoding example trainer log each DFlash-family variant's training metrics as draft/<name>, which also puts them in trainer_state.json. check_regression.py takes the first key containing "acc" in the last logged entry as the run's accuracy, and TrainerState.save_to_json writes that entry with sorted keys, so the draft/ keys come before train_acc/parallel_0_step_0, the key EagleTrainingPlot copies into the entry for this gate. MIN_FINAL_ACC would then silently start gating DFlash2, DSpark, Domino and LiLiCorr runs on a head diagnostic (selector_accuracy, backbone_accuracy, lilicorr_slot_acc) instead of the training accuracy its thresholds were chosen for: regression_check.json would report that diagnostic as the run's accuracy, and the DFlash2 online example, which runs the gate with REGRESSION_STRICT=1, would pass or fail its training task on it. Skip draft/* so the gate keeps reading train_acc. The new test_check_regression.py case writes such an entry, a draft/selector_accuracy of 0.09 beside a train_acc of 0.17, and fails without the skip, which reads 0.09. The file's 19 tests pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: h-guo18 <67671475+h-guo18@users.noreply.github.com>
…mple trainer Every DFlash-family training forward returns draft_metrics, but the example trainer never logged them, so DFlash2's selector_coverage, LiLiCorr's lattice diagnostics, DSpark's confidence_loss and Domino's lambda_base never reached TensorBoard or wandb. EagleTrainerWithAccLog now sums each metric as a tensor per micro-batch, so no host sync, and Trainer.log adds each name's mean over the steps that reported it as draft/<name>, with one sync per log step. It has to be Trainer.log, not EagleTrainingPlot.on_log: the HF reporters are callbacks registered ahead of ours, so a key added in on_log never reaches TensorBoard, and log_history is recorded before any callback runs, so such a key reaches trainer_state.json only by patching the recorded entry, as EagleTrainingPlot does for train_acc. train_acc therefore still never reaches TensorBoard; the comment saying it does is corrected, its handling left as is. The trainer names no variant or metric. Each rank averages its own steps, as for train_acc. The LiLiCorr weight description now says where the metrics are logged. Verified: - the new unit test, which fails on the parent with KeyError 'draft/step'; - DFlash, DFlash2, LiLiCorr, DSpark and Domino each trained through the real HF Trainer on GPU with report_to=tensorboard, on transformers 5.5.4, 5.12.1 and 5.18.0: every draft_metrics name lands as train/draft/<name> and in log_history, equal to the window mean of what the forwards returned, including a window with a step that had no supervised token; train_acc lands in log_history only; - on the trainer_state.json each of those runs saves, check_regression.py reads train_acc/parallel_0_step_0 as the accuracy; without the previous commit it reads draft/selector_accuracy (DFlash2), draft/lilicorr_slot_acc (LiLiCorr) or draft/backbone_accuracy (DSpark, Domino); - torch.cuda.set_sync_debug_mode: no sync in the per-step accumulation, one per log call that has metrics; - 2-rank gloo DDP through the HF Trainer: no hang, each rank logs its own means and rank 0 writes them to TensorBoard; - test_hf_speculative_offline.py, the DFlash-family plugin tests and the launcher's test_check_regression.py on transformers 5.5.4 and 5.18.0 (388 passed on each); - tests/gpu/torch/speculative/plugins (20 passed, 1 skipped); - bitwise A/B of all 23 DFlash-family cases and 15 more, fp32 and bf16, against the parent: 76 MATCH; - FSDP2 probe, dflash draft branch ce/kd: both ranks OK, same losses as the parent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: h-guo18 <67671475+h-guo18@users.noreply.github.com>
Users of examples/speculative_decoding get new draft/<name> scalars in TensorBoard, wandb and trainer_state.json; say what they are and that they are interval means. Checked with the rst pre-commit hooks. The entry goes under the 0.49.0 heading: release/0.48.0 is branched, so this change first reaches users in 0.49.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: h-guo18 <67671475+h-guo18@users.noreply.github.com>
|
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. |
Contributor
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Comment |
This was referenced Oct 24, 2026
Draft
This branch has not been deployed
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?
Type of change: New feature
Stacked on #2990 [2/2] (branch
haoguo/dflash-shared-forward, head 28f4f45), whose branch is the base; merge it after that one. There, every DFlash-family training forward returnsdraft_metrics, a dict of detached 0-dim tensors. Nothing logs them:EagleTrainerWithAccLogrecords onlytrain_accand EAGLE's component losses. So DFlash2'sselector_coverage, LiLiCorr's lattice diagnostics, DSpark'sconfidence_loss, Domino'slambda_baseand the objective terms never reach TensorBoard, wandb ortrainer_state.json.compute_lossadds each metric to a running sum per name. The sum stays a tensor, so there is no host sync per step.Trainer.logadds each name's mean over the steps that reported it tologs, asdraft/<name>. That costs one.tolist()sync per log step.Trainer.logand notEagleTrainingPlot.on_log. HF registers its reporters (TensorBoard, wandb, ...) as callbacks ahead of user callbacks, andTrainer.logcopieslogsintolog_historybefore any callback runs. A key added inon_logtherefore never reaches TensorBoard, and reachestrainer_state.jsononly by patching the recorded entry.train_acc/parallel_<i>_step_<j>travels on main: since specdec: stop the training regression gate passing unevaluated #2776,EagleTrainingPlot.on_logcopies it intolog_history[-1]for the regression gate. It reaches the console,trainer_state.jsonandEagleTrainingPlot's ownwandb.log, but not TensorBoard.Trainer.logis the hook HF documents for this ("Subclass and override this method to inject custom behavior").on_logcomment claimedtrain_accis "picked up by TensorBoard". It now says wheretrain_accactually goes. Its handling is unchanged.train_acc, and nothing is reduced across ranks. So there is no collective for a rank without metrics to hang. The reporters write rank 0's values.tools/launcher/common/check_regression.pyreads the last logged entry of the latest checkpoint'strainer_state.jsonand takes its first key containingaccas the run's accuracy; on main that key istrain_acc/parallel_0_step_0.TrainerState.save_to_jsonwrites the entry with sorted keys, so this PR'sdraft/*keys come first.MIN_FINAL_ACCwould start gating DFlash2, DSpark, Domino and LiLiCorr runs onselector_accuracy,backbone_accuracyorlilicorr_slot_acc, which its thresholds were not chosen for.regression_check.jsonwould report the diagnostic as the run'saccuracy. The Qwen3-8B DFlash2 online example runs the gate withREGRESSION_STRICT=1, so its training task would pass or fail on the selector's accuracy.draft/*and keeps readingtrain_acc. TheMIN_FINAL_ACCrow in the speculative-decoding skill'sreferences/algorithms/dflash.md, which the other DFlash-family references point to, notes the exception.dflash_lilicorr_w_cedescription now says where its metrics are logged, and there is a CHANGELOG entry under 0.49.0. DFlash2's comment that "the trainer converts them at the logging boundary" is now true as written.What each variant logs:
projector_typedraft/<name>loss_ceorloss_kdselector_accuracy,selector_coverageloss_ce,loss_tvd,backbone_accuracy,confidence_lossloss_final,loss_backbone,backbone_accuracy,lambda_baseloss_ceorloss_kd,origin_loss,origin_accuracyUsage
Nothing to configure. TensorBoard shows
train/draft/<name>, since HF prefixes training keys withtrain/.trainer_state.jsonkeeps the metrics too:Testing
test_trainer_logs_each_draft_metric_mean_per_windowintest_hf_speculative_offline.py, the unit module that already loadseagle_utils.Trainerloop throughEagleTrainerWithAccLog: 4 steps, 2 per log window. The model's second step reports no metrics.log_history, which records the dict the reporters receive. Each window must hold each name's mean, and a float64 metric must read back exactly.KeyError: 'draft/step', and takes 0.3 s on 4 CPUs (taskset -c 0-3).test_draft_metrics_are_not_the_accuracyintools/launcher/tests/test_check_regression.py. Its last log entry holdsdraft/selector_accuracy0.09 andtrain_acc/parallel_0_step_00.17, written with sorted keys as HF writes them. Against main'scheck_regression.pyit fails, reading 0.09.DominoLambdaCallback).EagleTrainerWithAccLogandEagleTrainingPlotwithreport_to=tensorboard. One batch had no supervised token.draft_metricsname appears astrain/draft/<name>in the TensorBoard event file and asdraft/<name>inlog_history. Each value equals the mean of what that window's forwards returned.train_accis inlog_historybut not in TensorBoard.torch.cuda.set_sync_debug_mode, the per-step accumulation does not sync, andlogsyncs once when it has metrics.trainer_state.json, main'scheck_regression.pyreadsdraft/selector_accuracy(DFlash2),draft/lilicorr_slot_acc(LiLiCorr) ordraft/backbone_accuracy(DSpark, Domino) as the accuracy. With this PR it readstrain_acc/parallel_0_step_0for all five. DFlash logs nodraft/*key containingacc.test_hf_speculative_offline.py,test_hf_{dflash,dflash2,dspark,domino,lilicorr}.pyandtools/launcher/tests/test_check_regression.py: 388 passed on each of transformers 5.5.4 and 5.18.0 (CI'stf_minandtf_latestpins), against 386 on the base.tests/gpu/torch/speculative/pluginson 1 GPU: 20 passed, 1 skipped. The skipped test needs 2 GPUs.pre-commit run --fileson the 7 changed files: clean.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.).CONTRIBUTING.md: N/AAdditional Information
Stack: #2757 ← #2762 ← #2989 [1/2] ← #2990 [2/2] ← this PR. Merge them in that order. Three other PRs sit on #2990 and are independent of this one: DSpark and Domino following
dflash_loss_objective(#2991), loss terms in config (#2993), and the shared AR-decode helper (#2994). This branch merges with each of them. The only conflict is inCHANGELOG.rstwith the loss-terms PR (#2993), where both add an entry to the same 0.49.0 list; keeping both entries resolves it.Not changed here:
train_accstill never reaches TensorBoard, for EAGLE as for the DFlash family, becauseEagleTrainingPlot.on_logadds it after the reporters have run. #2776 copied it intotrainer_state.jsonfor the gate. Adding it inTrainer.log, as this PR does fordraft/*, would also chart it in TensorBoard. That changes howtrain_accis handled, so it is left for a follow-up. The same holds forestimated_training_ar, which reaches only the console and wandb.🤖 Generated with Claude Code