fix(grpo): skip padding when trainset length is divisible by step size - #85
Open
detail-app[bot] wants to merge 1 commit into
Open
Conversation
Greptile SummaryCorrects GRPO trainset padding so datasets already divisible by the examples-per-step count do not receive an unnecessary full block of duplicate IDs.
Confidence Score: 5/5The PR appears safe to merge; the fix is narrowly scoped and preserves existing behavior for non-divisible trainset lengths. No actionable failures remain: aligned datasets now contain exactly one permutation per epoch, while indexing and batch-size invariants remain valid and are covered by regression tests. Important Files Changed
Reviews (1): Last reviewed commit: "fix(grpo): skip padding when trainset le..." | Re-trigger Greptile |
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.
Warning
GitHub issue creation failed
Detail attempted to publish this bug to GitHub, but the issue could not be created. This fix PR was created without that issue, and missing tracker references are shown as
Unknown issue.You can review and merge this PR normally. Please review your tracker integration settings before the next publish run.
Detail bug report: View on Detail
📝 Changes Description
This MR/PR contains the following changes:
GRPO.update_shuffled_trainset(dspy/teleprompt/grpo.py) pads the shuffled training-example ids so the total length is a multiple ofnum_dspy_examples_per_grpo_step(S). The padding-count formulaS - (N % S)returnsSinstead of0when the trainset lengthNis already divisible byS, so theif num_to_pad > 0guard never suppresses padding in the aligned case. This appends a full extra step worth of duplicate ids to the tail ofshuffled_trainset_ids.N % S == 0, each epoch is inflated fromNtoN + Sexamples. Once a training step's slice reaches the padded tail (gated onnum_train_steps * S > N, i.e. small trainsets or multi-epoch runs), one extra GRPO step per epoch trains on ids already seen earlier in that epoch, and the epoch/reshuffle boundary fires one step late. The bug is dormant forN >= num_train_steps * S(the defaultnum_train_steps=100, S=1config withN >= 100).S - (N % S)with the standard modulo formula(S - (N % S)) % S. This yields0in the aligned case and is identical to the old formula for everyN, SwithN % S != 0, preserving the divisibility invariant the shuffler relies on.tests/teleprompt/test_grpo.pythat the existing tests could not catch (they pass coincidentally under the bug because the padded block happens to be a full permutation of the dataset):test_grpo_dataset_shuffler_no_padding_when_divisible— asserts no padding is added whenN % S == 0.test_grpo_dataset_shuffler_across_epoch_boundary_divisible— drives the shuffler across an epoch boundary with a divisible(N=6, S=3)pair and asserts the epoch counter advances at the unpadded length, with each id appearing exactly once per epoch.Closes Unknown issue
✅ Contributor Checklist
uv run ruff checkclean on changed files; the only remaining ruff error ingrpo.pyis a pre-existingRUF017at line 576, unrelated to this change (verified pre-existing by stashing the fix).fix(grpo): skip padding when trainset length is divisible by step sizeAI disclosure: This change was authored by Detail: Automatic Fixes. The bug was identified via analysis of the padding arithmetic and confirmed by reproduction against the real
select_training_sample_and_update_shuffled_trainsetcode path.Testing notes:
uv run pytest tests/teleprompt/test_grpo.py -v(5 passed). A negative control (temporarily reverting the one-line fix) confirms both new tests fail on the buggy code while the three pre-existing tests still pass.N=100, S=1, num_train_steps=100) the consumed batches and RNG stream are byte-identical between the buggy and fixed versions — only the harmless internalshuffled_trainset_idslength (101 vs 100) andid_freqstotal differ, never read because no step reaches the padded tail.GRPO.compile()verification could not be run: the in-tree OpenAI provider raisesLMUnsupportedFeatureError(no in-tree provider implements thereinforceinterface), and the publishedarbor-ai==0.2.2does not export theArborGRPO/ArborProviderAPI the RL tutorial notebooks import. This is an upstream/infra gap, not a limitation of the fix; the unit tests exercise the sameselect_training_sample_and_update_shuffled_trainsetcode path (including the epoch-boundary/reshuffle trigger) thatcompile()calls.Automatic Fixes PRs can be configured here.