feat(algorithms): add AR PPO with GAE and value loss - #259
Conversation
Wire per-token critic values through Qwen3 replay and compute GAE advantages on RolloutTrack for the PPO critic path (issue Tencent-Hunyuan#86, part 2/3).
Keep transformers imports inside from_config / _packed_replay_supported as in upstream; only UniRL imports (ValueHead, ARReplayOutput) stay top-level.
Call _require_value_head_for_replay at the start of _replay_aware_forward so return_values=True fails fast before the transformer forward, not only from Qwen3ARStage.replay().
Extend ReplayResult with optional per-token values for PPO/GAE and replace ARReplayOutput in Qwen3 replay with the shared type.
Apply ruff-format changes and remove unused cu in _finalize_replay_output.
Derive last-token positions from packed offsets (end - 1) instead of passing redundant lengths, with a guard for empty samples.
a19512c to
c6c7681
Compare
c6c7681 to
c8f1afe
Compare
|
Updated the validation result with a real Qwen3-4B-Base end-to-end comparison on 8 x H20 (SGLang The run used 3 rollouts, batch size 8, 2 samples/prompt, 32 generated tokens, deterministic | rollout | SGLang loss | trainside loss | SGLang ratio | trainside ratio | SGLang mean Both paths completed all three updates without OOM, NaN, exception, or clipping. The maximum absolute loss difference was The earlier review fixes are preserved in
This is a short correctness comparison rather than a long-horizon convergence run. #259 remains draft until #256 is merged and the stack is rebased. |
Wire PPO.prepare_rollout_track for worker-side GAE, policy+value losses, advantage_mode=gae in AR trainers, and a Qwen3 DAPO recipe (issue Tencent-Hunyuan#86, 3/3).
c8f1afe to
7acd52d
Compare
|
Restored the original commit attribution without changing the tested code:
|
7acd52d to
cda2582
Compare
Summary
Part 3/3 of #86: add PPO with token-level GAE and a clipped value objective for AR training.
Stacked on #256. Merge #256 first, then rebase this branch onto
mainso the PR reduces to the single PPO/trainer commit.PPO/PPOConfigwith clipped policy loss and clipped critic loss.loss_maskconsistently to both actor and critic optimization and metrics.advantage_mode: grpo | gaeto both synchronous and asynchronous AR trainers.value_head.*tensors from SGLang weight sync.Related Issue
Part of #86. Depends on #256.
Test Plan
No PR-specific test files are included.
SKIP=no-commit-to-branch pre-commit run --all-files --show-diff-on-failure— all hooks passed.python -m compileall -q unirl— passed.ar/qwen3_ppo_4b_base_dapo_sglangwith placeholder dataset/model paths — passed.3 + 2tokens), rather than a mismatched full-batch forward;advantage_modewiring;PPO.prepare_segment -> prepare_part -> compute_loss_and_backwardpath.0.0;ratio_mean:1.0;L2=2.7303159).0.5.12.post1— passed:top_k=1, one nonzero-gradient PPO update per rollout;| rollout | SGLang loss | trainside loss | SGLang ratio | trainside ratio | SGLang mean
|Δlogp|| trainside mean|Δlogp||| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| 1 | -0.2223 | -0.2238 | 1.0048 | 0.9981 | 0.0114 | 0.0110 |
| 2 | -0.2206 | -0.2209 | 0.9988 | 1.0026 | 0.0120 | 0.0096 |
| 3 | -0.2199 | -0.2191 | 0.9996 | 0.9994 | 0.0066 | 0.0080 |
The maximum absolute loss difference was
1.5e-3. SGLang's rollout-to-replay log-probability drift stayed in the same range as trainside's own replay drift, so this smoke showed no additional numerical-precision regression from SGLang sync/replay.Compatibility / Risk
advantage_mode=grpoanduse_value_head=falseremain the defaults.advantage_mode: gae, and omit critic tensors from rollout sync.mainbefore marking it ready.Reviewer Notes
Review the anchor timing first: old values are frozen per planned micro before any update, reassembled, and then used to compute GAE once for the part. AI assistance was used; the final diff was reviewed and validated against the current repository state.
Checklist