Skip to content

perf: batch trajectory generation in a single model.generate call (issue #6 item 4) - #17

Closed
hai-pilgrim wants to merge 3 commits into
marksverdhei:mainfrom
hai-pilgrim:perf/batched-trajectory-generation
Closed

hai-pilgrim wants to merge 3 commits into
marksverdhei:mainfrom
hai-pilgrim:perf/batched-trajectory-generation

Conversation

@hai-pilgrim

Copy link
Copy Markdown

Summary

Addresses item 4 from issue #6 (Performance: training pipeline optimizations).

Previously training_step called _generate_trajectory in a Python loop, issuing one model.generate call per (message × trajectory) pair — B × T GPU round trips per step. This PR replaces that loop with a single batched call.

Changes

  • Added _generate_trajectories_batched(user_messages, num_trajectories) to PromptBakingTrainer
    • Repeats each user message num_trajectories times
    • Tokenizes all prompts with left-padding (required for generation so real tokens align at the right)
    • Issues one model.generate call for the entire batch
    • Decodes and pairs outputs back to source messages, filtering empty responses
    • Returns early on empty input without touching the tokenizer
  • Updated training_step to call _generate_trajectories_batched instead of the sequential loop

Impact

Scenario Before After
batch_size=1, num_traj=4 4 generate calls 1 generate call
batch_size=4, num_traj=4 16 generate calls 1 generate call

The speedup is most significant when batch_size > 1 or num_trajectories > 1, which are the common configurations.

Test plan

  • 5 new tests: pair types, message identity, trajectory repeat count, empty input guard, empty-response filtering
  • All 13 trainer tests pass

🤖 Generated with Claude Code

@marksverdhei

Copy link
Copy Markdown
Owner

Review

The core batched generation logic is sound — left-padding for model.generate is correct, and the single-call approach is a clear win over B×T sequential calls.

Issues to address:

1. Scope creep. This PR bundles ~160 lines of unrelated test additions (deps tests, data tests, KL tests) that overlap with dedicated test PRs (#18, #24, #29 — now merged). Please rebase onto main and drop the test additions that are already covered. The PR should only contain the batched generation changes + its own 5 trainer tests.

2. Misleading variable name. prompt_lengths (line ~188) is actually the padded sequence length (same for all samples since left-padding makes them uniform). Rename to padded_prompt_length or prompt_end_idx to avoid confusion.

3. Conflicts with #26. PR #26 tests training_step by mocking _generate_trajectory in a loop, but this PR replaces that loop with _generate_trajectories_batched. Once this merges, #26's tests break. This is noted for awareness — #26 will need updating.

Please rebase to resolve the overlapping test additions, and rename the variable. The core trainer changes look good.

marksverdhei and others added 2 commits March 29, 2026 17:48
…sue marksverdhei#6 item 4)

Previously training_step called _generate_trajectory once per (message,
trajectory) pair, issuing N*T separate model.generate calls.
This adds _generate_trajectories_batched which:

1. Repeats each user message num_trajectories times
2. Tokenizes all prompts with left-padding in one batch
3. Issues a single model.generate call for the whole batch
4. Decodes and pairs outputs back to their source messages

Reduces GPU-CPU round trips from B*T to 1 per training step, which is
meaningful when batch_size > 1 or num_trajectories > 1.

Also adds 5 tests covering: pair types, message identity, num_trajectories
repeat count, empty input, and empty-response filtering.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The variable holds the padded sequence length (input_ids.shape[1]),
not individual prompt lengths. Rename to avoid confusion with
the _get_prompt_lengths method which returns per-message token counts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@hai-pilgrim
hai-pilgrim force-pushed the perf/batched-trajectory-generation branch from f138681 to 6838ae9 Compare March 29, 2026 17:49
hai-pilgrim pushed a commit to hai-pilgrim/bakery that referenced this pull request Mar 29, 2026
PR marksverdhei#17 replaces the _generate_trajectory loop in training_step with a
single _generate_trajectories_batched call returning (msg, response)
tuples. Update all test mocks accordingly so tests remain valid after
marksverdhei#17 merges.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@marksverdhei marksverdhei left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The batched generation logic is solid and the variable rename looks good. However, this now conflicts with #20 (just merged) which refactored compute_loss/prediction_step into shared helpers (_compute_batched_kl, _prepare_pairs, etc.).

The conflict is in trainer.py — #20 restructured the methods that #17's training_step delegates to. Please rebase onto main. The _generate_trajectories_batched method and training_step changes themselves should apply cleanly; only the context around them shifted.

Will approve and merge once rebased.

@marksverdhei

Copy link
Copy Markdown
Owner

Closing — we're pivoting away from on-the-fly trajectory generation toward SFT datasets. This optimization targets code that's slated for removal. Thanks for the contribution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants