Feature/207 multiple weighted reward - #428
Open
Shik2024 wants to merge 6 commits into
Open
Conversation
Allow a training run to register multiple named reward functions with weights and emit each component plus the weighted total. --reward-fn-path is now repeatable with a path:weight suffix (default 1.0); a single unweighted value keeps the legacy single-reward path unchanged. - areno/api/rewards.py: add CompositeReward/CompositeScore (construction-time validation: duplicate names, bad/zero weights, error modes) with raise vs mark_invalid handling and weight-normalised totals; __call__ keeps the reward_fn(record)->float trainer contract. - trainers (policy_only, ppo): score through _score_reward so component breakdown is collected for diagnostics while the plain single-reward path stays byte-for-byte unchanged. - engine/data + metrics: route reward/<name>_mean and *_invalid_count through the existing TrainStats.metrics -> TensorBoard channel. - cli/train: multiple --reward-fn-path, --reward-on-error, preflight validation per component, and a human-readable component summary. - examples/math: accuracy_reward.py + format_reward.py (offline, no network). - tests: test_composite_reward_cpu.py (19 CPU cases covering math, validation, error modes, length alignment, example semantics). Co-Authored-By: Claude <noreply@anthropic.com>
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.
What does this PR do?
AReno's RL training previously supported only single-dimension, simple scoring:
areno train --reward-fn-pathaccepted a single reward file, each completion produced one scalar reward, and the dashboard exposed only the aggregaterollout/rewards_mean. This is fine for single objectives like GSM8K ("answer right/wrong"), but falls short for real, multi-dimensional scenarios — code generation needs both logical correctness and code style, while question answering / chat needs factual correctness and humanistic care and format compliance, etc.This PR makes
--reward-fn-pathrepeatable, with the formpath[:weight](weight defaults to 1.0), so users can register multiple named reward components in one run and combine them into a single final reward via weight-normalized summation. Each component's mean (reward/<name>_mean) and failure count (reward/<name>_invalid_count) are emitted as independent metrics through the existingtrain_stats → record_training_statschannel, surfacing on TensorBoard (train/reward/<name>_*), the CLI log, and the dashboard — so every dimension of the reward is individually observable.Design is byte-for-byte backward compatible: a single
--reward-fn-pathwithout:weightbehaves exactly as before.CompositeReward.__call__returnsscore().total, remaining a drop-in for thereward_fn(record)→floatcontract the trainer already uses; the branch happens inside_score_rewardviaisinstance, so noTrainer/Backendpublic signature orTrainerConfig.reward_fn_pathfield is touched.Main changes:
areno/api/rewards.py(newCompositeScore/CompositeReward),areno/cli/train.py(repeatable--reward-fn-path+--reward-on-error+ parsing/validation/assembly),areno/api/trainers/policy_only.pyandppo.py(per-component accumulation & metric injection; PPO reuses via inheritance),areno/api/metrics.py(reuses the existing write loop),examples/math/accuracy_reward.py+format_reward.py(multi-dimension demo), andtests/(new coverage).Related issue
Fixes #(issue)
Type of change
How was it tested?
New tests (CPU, no GPU required):
tests/test_composite_reward_cpu.py:CompositeRewardmath / validation / error modes / component access / example semantics / CLI parsing, plus a newTrainerComponentStatsTest(3 cases: multi-component emitsreward/<name>_mean,mark_invalidincrements the invalid count, and a plain single reward does not leak these keys).tests/test_metrics_cpu.py: newRewardComponentMetricsTestusing a FakeWriter to assertrecord_training_statswritestrain/reward/<name>_meanandtrain/reward/<name>_invalid_count.Commands to run (pending CI / Linux + Python 3.10+):
End-to-end smoke (requires GPU):
areno train --ckpt Qwen/Qwen3-0.6B --dataset-path gsm8k:main \ --dataset-loader-fn examples/math/dataset_loader.py \ --reward-fn-path examples/math/accuracy_reward.py:0.7 \ --reward-fn-path examples/math/format_reward.py:0.3 \ --algo gspo --tp-size 1 --world-size 1 --batch-size 1 # expected: train_stats contains reward/accuracy_reward_mean and reward/format_reward_meanHardware / environment limitations (disclosed honestly): the local checkout is on macOS with only the system Python 3.9;
pytest/pydantic/ruffare unavailable and the repo relies on@dataclass(slots=True)(needs 3.10+), so the test suite cannot be executed locally. Only static checks were run locally: all 5 changed files passpython3 -m py_compile, andgrep -rc _reward_components_legacy areno/ tests/returns 0 (dead code removed). Runtime pytest/ruff/pyright and the GPU smoke run are deferred to CI/Linux; no "tests pass" claim is made until CI confirms it.Checklist
pytest tests/ -k cpu).Breaking change details
None. This PR is purely additive and backward compatible: the single-reward usage is byte-for-byte unchanged;
--reward-fn-pathonly goes from single-value to repeatable (option name unchanged) with a new additive--reward-on-errorswitch;CompositeReward/CompositeScoreare new SDK exports that do not alter any existingTrainer/Backend/TrainerConfigpublic surface.