[No.29] register, verify and document REINFORCE++ / REINFORCE++-baseline - #178
[No.29] register, verify and document REINFORCE++ / REINFORCE++-baseline#178howtomakeaname wants to merge 8 commits into
Conversation
…infra#29) The REINFORCE++ / REINFORCE++-baseline advantage functions already existed in ppo_utils.py, but the variants were not registered in ALGOS, so the Controller rejected the key ("Algorithm key 'reinforce_plus_plus' not registered in ALGOS") and they could not run end-to-end. Register both variants reusing the GRPO topology (no critic), and factor the duplicated GRPO-family topologies into a shared _GRPO_TOPOLOGY constant (single source of truth). Add registry tests covering registration, topology reuse, and process_role dispatch.
Add element-wise parity tests against independent plain-torch reference implementations for get_reinforce_plus_plus_returns, get_reinforce_plus_plus_baseline_advantages, and the shared compute_policy_loss. Coverage: variable-length responses, all-zero rewards, single-sample batches, gamma discount, mask not polluting prompt/padding, fully-masked rejection. Add distributed tests (fake mpu + mocked primitives, single process): CP gather/compute/slice wiring of the returns (zig-zag chunking is cp_utils' responsibility and out of scope), baseline CP locality, and DP partition invariance of masked advantage whitening.
…ings Add docs/algorithms/reinforce_plus_plus.md covering formulas, normalization dimensions, mask and reduction semantics, variant comparison vs GRPO/GSPO/SAPO, CP/DP behavior, and the known async-path whitening limitation. Make the group-baseline convention explicit in code: docstrings on get_reinforce_plus_plus_returns / get_reinforce_plus_plus_baseline_advantages and a comment in post_process_rewards clarify that the baseline is subtracted upstream (group-mean, no std, unlike GRPO) and that advantage whitening is applied only in the sync path. No behavior change.
Add single-GPU colocate quickstart recipes for Qwen3-0.6B on GSM8K, based on the GRPO quickstart and switching --advantage-estimator to reinforce_plus_plus / reinforce_plus_plus_baseline with --normalize-advantages.
Apply docformatter (wrap-descriptions 79) to the new REINFORCE++ test modules so the pre-commit hook passes in CI. Docstring-only changes.
a18a1a0 to
a384cfa
Compare
|
实验尚不完整,暂不通过,主要有两个问题需要补一下:
这实际上等于没有启用 KL。与此同时,文档里又写了普通版本把 KL 放进 token return、baseline 版本把 KL 放进 advantage,所以当前 recipe、文档和算法定义对不上,现有训练结果也没有真正验证文档描述的完整算法。 麻烦先明确这里到底是遵循原论文,还是采用 Relax 自己定义的 convention。如果遵循论文,baseline 版本应该是 group mean + global advantage normalization + 独立 k2 KL loss;如果采用 Relax 自己的定义,也请把实现、
另外有个小问题:脚本开头写的是 100 × 4 × 4 / 16 = 100 steps,但默认 N_SAMPLES=8,实际应该是 200 steps,也请顺手修正。 其他部分没什么大问题:两个 estimator 注册正确,复用 GRPO 的无 critic topology 也合理;新增和相关回归测试本地共 34 条通过,GitHub CI 也都是绿的。把上面的算法口径和实验材料补齐后,再看是否可以合入。 |
Per review of redai-infra#178: the v1 recipes set --use-kl-loss --kl-loss-coef 0.00 and left --kl-coef at its 0.00 default, which effectively disabled KL entirely, contradicting the design doc per-token KL formulas and leaving the documented algorithm unverified in training. Follow arXiv:2501.03262 for both variants: - reinforce_plus_plus (section 3.1): keep the k1-style per-token KL penalty folded into the discounted return (--kl-coef 0.001 --kl-loss-type k1). - reinforce_plus_plus_baseline (section 3.2): group-mean baseline + global advantage whitening + a separate k2 KL loss (--use-kl-loss --kl-loss-type k2 --kl-loss-coef). get_reinforce_plus_plus_baseline_advantages no longer folds -kl_coef * kl into the advantage; the kl_coef parameter is removed and both call sites updated. arguments.py now rejects --kl-coef != 0 for the baseline estimator so the silent no-KL configuration cannot recur. Also updates the design doc (sections 2/3/4/5/8/9), the reference implementation and tests (KL must not enter the baseline advantage), both recipes (non-zero KL; header step math corrected to 100 x 4 x 8 / 16 = 200), and docstrings.
- .opencode agent cheat sheet: REINFORCE++-baseline is a group-mean baseline (paper section 3.2), not a leave-one-out baseline (which is neither what post_process_rewards implements nor what the paper defines). - design doc section 8: point the GRPO comparison recipe at its canonical location in redai-infra/community instead of the local-only copy.
|
@RexFlux 感谢审阅,已根据审阅修复,辛苦再Review下~
同时,步数注释已修正为 100 × 4 × 8 / 16 = 200 steps,注册、拓扑复用、测试未改动,CI(pre-commit / lint / tests)通过。 |
Per review findings: section 6.3 now states the variants are rejected (not merely un-normalized) in fully-async mode; remove the duplicated paragraph in section 9; correct the recipe header note (train/ppo_kl is on-policy drift, not the folded KL penalty - which shows up as returns - raw_reward).
What
Register the
reinforce_plus_plus/reinforce_plus_plus_baselinealgorithm variants inALGOS, add numerical and distributed tests, a design doc, and colocate recipes.Why
Closes #177.
The advantage functions for REINFORCE++ / REINFORCE++-baseline already existed in
ppo_utils.py, but the two variants were never registered inALGOS, so the Controller rejected the key (Algorithm key 'reinforce_plus_plus' not registered in ALGOS) and they could not run end-to-end. This makes them runnable and verifiable, and pins the formulas, normalization dimensions, mask and reduction semantics in a design doc and tests to resolve the "naming and baseline convention are not unified" gap flagged by task #29.How
relax/core/registry.py): register both variants reusing the GRPO topology (no critic); factor the duplicated GRPO-family topologies into a shared_GRPO_TOPOLOGYconstant (single source of truth — registry dispatch instead of if/elif). Behavior-equivalent for existing algorithms.reinforce_plus_plus(§3.1): per-token k1-style KL penalty (--kl-loss-type k1) folded into the discounted return via--kl-coef; global advantage whitening via--normalize-advantages. No group baseline.reinforce_plus_plus_baseline(§3.2): group-mean baseline (upstream inpost_process_rewards, no std division) + global advantage whitening + separate k2 KL loss (--use-kl-loss --kl-loss-type k2 --kl-loss-coef) — the KL penalty is NOT folded into the advantage.get_reinforce_plus_plus_baseline_advantagesno longer subtracts-kl_coef * kl(signature dropskl_coef; call sites inloss.py/advantages.pyupdated);arguments.pynow rejects--kl-coef != 0for the baseline estimator so the "silently no KL" configuration (v1 recipes) cannot recur.tests/utils/training/test_ppo_utils_reinforce.py— element-wise parity vs independent plain-torch reference implementations for the returns, baseline advantages, and the sharedcompute_policy_loss. Covers variable-length responses, all-zero rewards, single-sample batches, gamma discount, mask not polluting prompt/padding, fully-masked rejection, and the paper convention that per-token KL does NOT enter the baseline advantage.tests/backends/megatron/test_reinforce_pp_cp_parity.py— CP gather/compute/slice wiring of the returns (zig-zag chunking iscp_utils' responsibility, out of scope), baseline CP locality, and DP partition invariance of masked advantage whitening (fakempu+ mocked collectives, single process, pertest_ppo_gae_parity.pyconvention).tests/core/test_registry_reinforce.py— registration, topology reuse, no critic,process_roledispatch.docs/algorithms/reinforce_plus_plus.md): formulas, normalization dimensions, mask and reduction semantics, variant comparison vs GRPO/GSPO/SAPO, CP/DP behavior, and the known async-path whitening limitation. §3.1/§3.2/§4/§5 updated to the paper convention (k1 folded penalty forreinforce_plus_plus; separate k2 KL loss for the baseline variant).examples/algorithms/run-qwen3-0.6B-1xgpu-reinforce-pp.sh(--kl-coef 0.001 --kl-loss-type k1) and...-reinforce-pp-baseline.sh(--use-kl-loss --kl-loss-coef 0.001 --kl-loss-type k2), switching--advantage-estimatorand adding--normalize-advantages; header step math fixed to100 × 4 × 8 / 16 = 200.post_process_rewards, group-mean without std unlike GRPO; whitening applied only in the sync path).Testing
20 new tests pass; 14 regression tests (
test_ppo_utils_grpo.py,test_registry_sft.py) pass.ruff check/ruff format --check/docformatterclean (CI's pinned ruff 0.15.9).End-to-end training comparison with non-zero KL per the paper convention (Qwen3-0.6B + GSM8K, same budget, sync colocate, 3 seeds {1234, 42, 7}, 40 steps each, mean±std over stable region steps 5–39):
All three stable (9/9 runs 40/40 steps, 0 NaN/Inf, 0 dropped samples); pg_loss / grad_norm / KL metrics are clearly distinct across algorithms, confirming
--advantage-estimatoractually switches the algorithm. Step time 12.4–13.3 s (samples/s 1.21–1.29, GBS 16) — budget-fair; GRPO reproduces the v1 numbers under the same seed/config (no regression from the changes). All 9 logs and 6 curve figures are included in the task-questionnaire (wps) submission bundle.Reproducibility materials (reviewer request): complete per-algorithm/per-seed commands, stats interval (steps 5–39), step time, and the 9 raw logs are listed in the training report (
deliverables/training-report.md); logs archive:redai-test/runs/log-{grpo,reinforcepp,reinforcepp-baseline}-seed{1234,42,7}.txt(also bundled as a gist for the review thread). No NaN/Inf, no dropped samples, effective batch/seq-len unchanged — evidence extracted from the logs and tabulated in the report.Type of Change
Notes
--advantage-estimator/--normalize-advantages.