Conversation
- Use lazy evaluation in testing model path dictionaries to avoid eager downloads on test collection - Safely handle PackageNotFoundError in version check helper functions
…oup normalization - In multi-turn rollouts (len(result) > 1), only normalize the terminal interaction that supplied the rollout outcome reward, preserving intermediate step-level rewards - Prevent overwriting pre-existing interaction.original_reward baselines - Synchronize normalized values and original rewards to interaction._cache - Add unit tests verifying intermediate step-level reward preservation, original_reward retention, and single-turn parity
|
Could you clarify the intended training objective here? In the v2 export path, reward discounting runs before normalization, so earlier interaction rewards may already represent returns that include future rewards, rather than independent step scores. |
Default to the historical broadcast behavior so outcome-only rollouts keep their existing training semantics, and add an opt-in "terminal" policy for rollouts that carry genuine step-level rewards.
079a737 to
12ccd72
Compare
|
You're right, and thanks for catching it. After I've made the policy explicit instead. The one remaining behavior change is |
| class _LazyModelDict(dict): | ||
| """Dictionary that lazily resolves model paths upon access.""" | ||
|
|
||
| def __init__(self, specs: dict[str, tuple[str, str]]): | ||
| super().__init__() | ||
| self._specs = specs | ||
|
|
There was a problem hiding this comment.
The unrelated changes to testing_utils.py and pkg_version.py are still present here.
Please review all related PRs and remove these changes wherever they remain, rather than addressing them one PR at a time. Please also check each PR's full diff for scope and correctness before requesting another review.
These files are not part of group-reward normalization and already landed on main via areal-project#1568.
Description
In multi-turn agent rollouts (e.g. tool-using agents exported with
style='individual'), an episode contains multiple interactions across successive turns (e.g., tool-call turns with intermediate step rewards, followed by a final answer turn with an outcome reward).Previously,
normalize_group_rewardsinareal/experimental/openai/types.pycomputed group statistics from the last interaction of each rollout (last_id = next(reversed(result))), but then looped over every interaction in the episode:This caused two critical issues:
Every intermediate interaction in the episode (e.g., Turn 1 penalty of
-0.2) was completely overwritten by the terminal turn's normalized outcome reward (e.g.,+1.0). Intermediate turns lost their distinct reward attribution and were falsely assigned the final answer's normalized score.interaction.original_rewardwas unconditionally assignedinteraction.reward, destroying any previously recorded raw reward baselines (e.g. from prior reward discounting or step-level evaluation).This PR fixes these issues:
len(result) > 1), only the terminal interaction (cid == last_id) that provided the group outcome score is updated with the group-normalized reward. Intermediate interactions preserve their distinct step-level rewards and attribution.original_reward:interaction.original_rewardis only set if it was not already populated.interaction._cache.len(result) == 1) or concat-mode rollouts maintain 100% numerical and behavioral equivalence with baseline.Verification Plan
tests/experimental/openai/test_normalize_group_rewards.py:test_multi_turn_preserves_intermediate_step_rewards: verifies intermediate step rewards are preserved while terminal turn is normalized.test_existing_original_reward_not_overwritten: verifies pre-existing raw reward baselines are retained.test_single_turn_exact_parity: verifies numerical identity on single-turn groups.test_empty_or_incomplete_group_handling: verifies handling of missing/None rewards.uv run pytest tests/experimental/openai/test_normalize_group_rewards.py tests/experimental/openai/test_cache.py(16 passed).pre-commithooks (ruff check,ruff format,check-yaml, etc.).