feat: add Energon-owned SFT sequence packing - #4070
Conversation
|
Auto-sync is disabled for ready for review pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
Signed-off-by: rohitrango <rohit.rango@gmail.com>
Signed-off-by: rohitrango <rohit.rango@gmail.com>
Signed-off-by: rohitrango <rohit.rango@gmail.com>
Signed-off-by: rohitrango <rohit.rango@gmail.com>
Signed-off-by: rohitrango <rohit.rango@gmail.com>
58002b0 to
da8a263
Compare
|
/ok to test da8a263 |
rohitrango
left a comment
There was a problem hiding this comment.
Reviewed by a team of five agents (RL codebase, Megatron-Core/Bridge/Energon upstream, bug scan, tests, plus an adversarial pass that re-derived every finding from source and dropped six that did not survive).
Nice piece of work — moving packing ownership into the Energon task encoder is the right shape for SFTv2, it keeps media travelling with the pack instead of over the wire in padded rows, and the convergence curves for both models are a good thing to have up front.
Please look at the four blocking items first (all reproduced locally):
balanced_knapsack_delta=20is the shipped default and both recipes select that packer — 1.6x-3.2x more microbatches at ~30-57% bin utilization, with no config path to change it.- Any conversation longer than
data.max_input_seq_lengthraises out of the packer and ends the job, becausepacking_costkeeps the pre-truncation length. The non-packing path handled the same sample gracefully. - Four existing test files break and were not updated —
tests/unit/algorithms/test_sft_v2.py(6 failures),tests/unit/models/policy/test_tq_policy_placed.py(1),tests/unit/data/test_energon_sft.py(3),tests/unit/data/test_energon_sft_v2.py. Verified by running the first two and by execution/AST for the rest. - Both new recipe YAMLs turn
test_all_recipe_yamls_accounted_for_in_test_suitesred — that module isrun_first, so it is an L0 break.
On evidence: the convergence curves establish that packing does not break training, which is the harder half. What is missing is any number showing the feature does its job — tokens/s or step time, peak memory, and mean bin utilization, packed vs unpacked. get_packer is called without collect_metrics, so PackingMetrics never runs and the feature currently ships with no way to observe what it packed. A three-row table would also have surfaced items 1 and the greedy_knapsack question below before review. (Worth noting the Qwen packing run stopped at step 36 against 50 for the others.)
Checked and clean, recorded so nobody re-derives them: the GreedyKnapsackPacker bisect sentinel (brute-forced against a naive reference over 3000 cases, 0 mismatches); the per-source loss-mask shift, which correctly zeroes every source's first token; sample_mask per physical pack for loss normalization; data.size and the MICRO_BATCH_INDICES / MICRO_BATCH_LENGTHS nesting; the sample_schema removal (zero readers anywhere); packing_buffer_size as a kwarg on all three Energon loader entry points; Sample.derive_from with the extra fields; and max_seqlen_q, total_tokens and position_ids=None against Megatron-Core at the pinned SHA. No upstream defects found in Megatron-LM, Megatron-Bridge or megatron-energon — nothing to file.
Ruff format and Ruff lint both pass on the changed files.
Generated by Claude Code
Signed-off-by: Rohit Jena <rohitrango@users.noreply.github.com>
Signed-off-by: rohitrango <rohit.rango@gmail.com>
Signed-off-by: rohitrango <rohit.rango@gmail.com>
|
Review follow-up: the full code/test/doc fixes are pushed in |
Signed-off-by: rohitrango <rohit.rango@gmail.com>
Signed-off-by: rohitrango <rohit.rango@gmail.com>
|
/ok to test f8eaef7 |
Signed-off-by: rohitrango <rohit.rango@gmail.com>
|
/ok to test 619c3d6 |
Summary
The implementation adds ~600 nonblank, non-comment Python lines. Configs and tests are excluded from that count.
Validation
Convergence

Qwen2.5VL with and without packing
Nemotron-Omni with and without packing and CP>1
