Skip to content

Commit 132680f

Browse files
author
Pooya Moradi
committed
Add reward_functions_path + reward_functions CLI knobs for custom rewards
Currently the reward stack is hardcoded to a 3-fn list: [match_format_exactly, match_format_approximately, check_numbers]. Replacing it requires editing train_rl.py. Add two new config fields: - reward_functions_path: path to a user Python file - reward_functions: comma-separated list of function names to import When both are set, the built-in reward stack is REPLACED entirely by the user-provided functions (so users can pin a single VTC-style partial-credit reward, swap in a math_verify-based scorer, etc., without editing maxtext). Each user function must accept (prompts, completions, tmvp_config, **kwargs) and return a list of floats. Default (both empty) keeps existing behavior unchanged. Reuses `_load_custom_callable` helper added in the previous commit.
1 parent be7748b commit 132680f

3 files changed

Lines changed: 43 additions & 5 deletions

File tree

src/maxtext/configs/post_train/rl.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,13 @@ eval_dataset_name: 'openai/gsm8k'
238238
# tmvp_config, x) -> dict with keys {prompts, question, answer}. When empty
239239
# (default), the built-in utils_rl.process_data is used.
240240
dataset_processor_path: ''
241+
# Optional: path to a user-provided Python file with custom reward functions,
242+
# AND a comma-separated list of function names to import from that file.
243+
# Each function signature: fn(prompts, completions, tmvp_config, **kwargs) -> list[float].
244+
# When both are set, the built-in [match_format_exactly, match_format_approximately,
245+
# check_numbers] reward list is REPLACED entirely.
246+
reward_functions_path: ''
247+
reward_functions: ''
241248
train_split: 'train'
242249
eval_split: 'test'
243250
hf_name: 'main' # subset of Hugging Face dataset

src/maxtext/configs/types.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2056,6 +2056,20 @@ class RLDataset(BaseModel):
20562056
"When set, replaces the built-in dataset processor for custom datasets."
20572057
),
20582058
)
2059+
reward_functions_path: str = Field(
2060+
"",
2061+
description=(
2062+
"Optional path to a user Python file containing custom reward functions. "
2063+
"Used with `reward_functions` to fully replace the built-in reward stack."
2064+
),
2065+
)
2066+
reward_functions: str = Field(
2067+
"",
2068+
description=(
2069+
"Comma-separated names of reward functions to import from `reward_functions_path`. "
2070+
"Each function signature: (prompts, completions, tmvp_config, **kwargs) -> list[float]."
2071+
),
2072+
)
20592073

20602074

20612075
class RLEvaluation(BaseModel):

src/maxtext/trainers/post_train/rl/train_rl.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -526,11 +526,28 @@ def _reward_fn(**kwargs):
526526

527527
return _reward_fn
528528

529-
reward_fns = [ # type: ignore
530-
make_reward_fn(utils_rl.match_format_exactly),
531-
make_reward_fn(utils_rl.match_format_approximately),
532-
make_reward_fn(utils_rl.check_numbers),
533-
]
529+
# Optional user-provided reward functions. `reward_functions_path` is a
530+
# filesystem path to a Python file. `reward_functions` is a comma-separated
531+
# list of function names to import from that file. Each function must accept
532+
# `prompts`, `completions`, `tmvp_config`, and `**kwargs` and return a list
533+
# of floats.
534+
# When both are set, the built-in reward_fns list below is REPLACED entirely
535+
# by the user-provided functions (so users have full control over their
536+
# reward stack — match the GPU recipe by passing your own vtc reward fn).
537+
_custom_rewards_path = getattr(trainer_config, "reward_functions_path", "") or ""
538+
_custom_rewards_names = getattr(trainer_config, "reward_functions", "") or ""
539+
if _custom_rewards_path and _custom_rewards_names:
540+
_names = [n.strip() for n in _custom_rewards_names.split(",") if n.strip()]
541+
reward_fns = [make_reward_fn(utils_rl.load_custom_callable(_custom_rewards_path, n)) for n in _names]
542+
max_logging.log(
543+
f"reward_fns: using {len(reward_fns)} custom reward function(s) " f"{_names} from {_custom_rewards_path}"
544+
)
545+
else:
546+
reward_fns = [ # type: ignore
547+
make_reward_fn(utils_rl.match_format_exactly),
548+
make_reward_fn(utils_rl.match_format_approximately),
549+
make_reward_fn(utils_rl.check_numbers),
550+
]
534551

535552
# Create RL trainer
536553
max_logging.log("Setting up RL trainer...")

0 commit comments

Comments
 (0)