-
Notifications
You must be signed in to change notification settings - Fork 311
feat(rm): allow per-sample custom_rm_path override #1637
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,6 +29,10 @@ async def remote_rm(args, sample: Sample): | |
|
|
||
|
|
||
| async def async_rm(args, sample: Sample, **kwargs): | ||
| if sample.custom_rm_path: | ||
| rm_function = load_function(sample.custom_rm_path) | ||
| return await rm_function(args, sample, **kwargs) | ||
|
|
||
| if args.custom_rm_path is not None: | ||
| rm_function = load_function(args.custom_rm_path) | ||
| return await rm_function(args, sample, **kwargs) | ||
|
|
@@ -88,10 +92,28 @@ async def batched_async_rm( | |
| sample.reward = reward | ||
| return None | ||
|
|
||
| if args.custom_rm_path is not None: | ||
| samples_with_overrides = [(index, sample) for index, sample in enumerate(samples) if sample.custom_rm_path] | ||
| if not samples_with_overrides and args.custom_rm_path is not None: | ||
| # Ensure the custom reward function is implemented in batch mode | ||
| rm_function = load_function(args.custom_rm_path) | ||
| return await rm_function(args, samples, **kwargs) | ||
| tasks = [async_rm(args, sample, **kwargs) for sample in samples] | ||
| rewards = await asyncio.gather(*tasks) | ||
| return rewards | ||
|
|
||
| samples_without_overrides = [(index, sample) for index, sample in enumerate(samples) if not sample.custom_rm_path] | ||
| override_rewards = asyncio.gather(*(async_rm(args, sample, **kwargs) for _, sample in samples_with_overrides)) | ||
| if args.custom_rm_path is not None and samples_without_overrides: | ||
| rm_function = load_function(args.custom_rm_path) | ||
| default_rewards = rm_function(args, [sample for _, sample in samples_without_overrides], **kwargs) | ||
| else: | ||
| default_rewards = asyncio.gather( | ||
| *(async_rm(args, sample, **kwargs) for _, sample in samples_without_overrides) | ||
| ) | ||
|
|
||
| override_rewards, default_rewards = await asyncio.gather(override_rewards, default_rewards) | ||
| rewards_by_index = dict( | ||
| zip( | ||
| [index for index, _ in samples_with_overrides] + [index for index, _ in samples_without_overrides], | ||
| [*override_rewards, *default_rewards], | ||
| strict=True, | ||
| ) | ||
| ) | ||
| return [rewards_by_index[index] for index in range(len(samples))] | ||
|
Comment on lines
+101
to
+119
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current implementation of
We can simplify the logic by flattening the samples_without_overrides = [(index, sample) for index, sample in enumerate(samples) if not sample.custom_rm_path]
override_tasks = [async_rm(args, sample, **kwargs) for _, sample in samples_with_overrides]
if args.custom_rm_path is not None and samples_without_overrides:
rm_function = load_function(args.custom_rm_path)
batch_task = rm_function(args, [sample for _, sample in samples_without_overrides], **kwargs)
import inspect
if inspect.isawaitable(batch_task):
results = await asyncio.gather(*override_tasks, batch_task)
override_rewards = results[:len(override_tasks)]
default_rewards = results[len(override_tasks)]
else:
results = await asyncio.gather(*override_tasks)
override_rewards = results
default_rewards = batch_task
else:
non_override_tasks = [async_rm(args, sample, **kwargs) for _, sample in samples_without_overrides]
results = await asyncio.gather(*override_tasks, *non_override_tasks)
override_rewards = results[:len(override_tasks)]
default_rewards = results[len(override_tasks):]
rewards_by_index = dict(
zip(
[index for index, _ in samples_with_overrides] + [index for index, _ in samples_without_overrides],
[*override_rewards, *default_rewards],
strict=True,
)
)
return [rewards_by_index[index] for index in range(len(samples))] |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While
async_rmnow correctly prioritizessample.custom_rm_pathoverargs.custom_rm_path,batched_async_rm(defined later in this file) does not.Specifically, in
batched_async_rm:If a global
args.custom_rm_pathis configured,batched_async_rmwill unconditionally route all samples to that global custom RM, completely ignoring any per-samplesample.custom_rm_pathoverrides. This breaks the core objective of supporting mixed-task batches with different reward functions.To fix this,
batched_async_rmshould group the samples by their effective custom RM path (eithersample.custom_rm_pathorargs.custom_rm_path) and batch them accordingly, falling back to individualasync_rmcalls for samples that do not use any custom RM.Here is a suggested implementation for
batched_async_rm: