Add optional process-pool evaluation of reward functions - #1904
Draft
gutianyu-google wants to merge 1 commit into
Draft
Add optional process-pool evaluation of reward functions#1904gutianyu-google wants to merge 1 commit into
gutianyu-google wants to merge 1 commit into
Conversation
Sequence-level reward functions are pure Python evaluated serially over the whole batch on one core, while the host's remaining cores idle. On a GRPO benchmark (2048 sequences/step, 3 reward functions) this serial pass took 29.6 s of a 155.6 s step. This change adds AlgorithmConfig.reward_num_workers (default 0 = serial, preserving current behavior bit-for-bit). When > 1, SequenceRewardManager evaluates each reward function over contiguous chunks of the batch in a fork-based process pool and concatenates the results in order, so per-sequence reward functions produce identical results. kwargs that are per-example columns (len == num_prompts, e.g. ground-truth answers) are sliced in lockstep; scalars pass through. Robustness: functions that cannot run in a worker (unpicklable, or spawning subprocesses of their own, which daemonic pool workers forbid) are detected at runtime and evaluated in the parent process from then on; pool-creation failure or any other error falls back to the serial implementation. TUNIX_REWARD_PARALLEL=0 disables the pool at runtime. Measured on the same benchmark with reward_num_workers=32: reward computation 29.6 s -> ~3.5 s and global step 155.6 s -> 129.0 s, with rewards byte-identical to the serial run over all 20 steps. (One of the three functions dispatches to its own subprocess pool and therefore ran in the parent via the fallback; widening that internal pool contributed part of the win.)
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
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.
Sequence-level reward functions are pure Python, evaluated serially over the whole batch on one core while the host's remaining cores idle. On a GRPO post-training benchmark (qwen3-0.6b, 2048 sequences/step, 3 reward functions on a 40+ core head node), this serial pass took 29.6 s of a 155.6 s global step — the second-largest component after rollout.
This PR adds
AlgorithmConfig.reward_num_workers:0keeps the serial implementation and preserves current behavior bit-for-bit.> 1,SequenceRewardManagerevaluates each reward function over contiguous chunks of the batch in a fork-based process pool and concatenates results in order. Per-sequence reward functions therefore produce identical results to the serial path. kwargs that are per-example columns (len == num_prompts, e.g. ground-truth answer lists) are sliced in lockstep with the batch; everything else passes through unchanged.Robustness, all covered by unit tests:
forkstart method all fall back to the serial implementation with one warning.TUNIX_REWARD_PARALLEL=0disables the pool at runtime without a config change.Measured (same benchmark,
reward_num_workers=32): reward computation 29.6 s → ~3.5 s, global step 155.6 s → 129.0 s (−17%), with per-step rewards byte-identical to the serial run over all 20 steps (max abs diff 0.000000). One of the three reward functions dispatches to its own subprocess pool and ran in the parent via the fallback; widening that internal pool contributed part of the win.Reference
Benchmark context: MaxText GRPO post-training on TPU v7x; reward functions are the
match_format_*/check_numbersfamily from MaxText's RL utils.Checklist