Repository navigation
[XPU] add in scheduler.avg with patch, not dependent on verl-core - #32
Merged
physics31415926 merged 11 commits intoSep 30, 2026
Conversation
Split out of experiment/xpu-monkeypatch-no-core-hooks: covers is_reduce_avg_supported (FSDP2 per-layer loop, no patch needed; raw dist.all_reduce(AVG), patched) and attention_utils_module. Both work with zero verl-core changes, independent of the VTune profiler half (docs/design/xpu-monkeypatch-vtune-profiler.md), which still has an open blocker. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
5 of 6 tasks
…atch attention_utils_module() is staying a PlatformBase hook (see PR #22, and verl-project/verl#7917's updated description) -- it passed the maintainer's bar on verl-hardware-plugin#26 for a genuinely hardware-agnostic capability that couldn't be done cleanly from the plugin alone. Carrying a monkeypatch alternative for it here too just duplicates an already-accepted, working solution with no benefit. is_reduce_avg_supported() didn't pass that bar and is this branch's actual job: the xccl AVG gap can be fully handled from the plugin (FSDP2 via an engine-level method override, the 3 remaining raw dist.all_reduce(op=AVG) sites via a scoped, documented monkeypatch). Renamed the design doc to match (xpu-monkeypatch-reduce-avg.md) and folded in a note that this branch is now the sole owner of the fsdp_xpu.py self.model->self.module fix -- it's been dropped from #22's smaller, root-only version of the same fix now that #22 no longer touches this file for any other reason.
kahlun
added a commit
to kahlun/verl-hardware-plugin-fork
that referenced
this pull request
Sep 24, 2026
…erl-project#32 Redundant scope: this PR no longer touches fsdp_xpu.py for any AVG-related reason (is_reduce_avg_supported was dropped in the previous commit), and that file's only remaining purpose here was this one attribute fix, which lives entirely in the pre-existing (pre-#22) reduce_avg workaround code. experiment/xpu-monkeypatch-reduce-avg-attention already carries the same fix as part of a strict superset (root + every per-layer FSDP2 wrapper, vs. this PR's root-only version) -- keeping both risks two PRs racing to fix the same lines. Leaving this PR to attention_utils_module and the VTune profiler hooks only.
7 of 8 tasks
verl_hardware_plugin/__init__.py is shared across every vendor in this plugin, so calling apply_all_patches() there fired the patch on any host where torch.xpu merely happened to be importable -- regardless of which platform verl actually selected for the run. A mixed host with e.g. VERL_PLATFORM=nvidia set explicitly would still get its process-wide torch.distributed.all_reduce(op=AVG) semantics changed for no reason, compounding the design smell this patch already carries. verl.plugin.platform.platform_manager._create_platform() only constructs PlatformXPU() once platform detection has actually picked "intel" for this process, so moving the call into PlatformXPU.__init__ ties it to real platform selection instead. The narrow remaining edge case -- auto-detection probing PlatformXPU() to check availability, then falling through to a different platform -- is self-mitigating: the patch's own _xpu_available() gate fails in the same underlying probe that made is_platform_available() fail. Also: - Add unit tests for both the new wiring (PlatformXPU() triggers the patch; the plugin's top-level __init__ no longer binds it directly) and the reduce_avg_allreduce_patch_xpu wrapper itself (AVG -> SUM+divide, other ops pass through unchanged, async_op=True falls through unpatched, no-op when XPU unavailable, idempotent). 75 passed. - Remove docs/design/xpu-monkeypatch-reduce-avg.md. This repo has no precedent for keeping RFC/experiment-verdict docs in the merged tree (confirmed: no docs/design/ directory exists on main, in any prior PR). Its reasoning already lives in this PR's description.
3 of 6 tasks
…irectly apply_all() had exactly one caller (PlatformXPU.__init__) and exactly one patch module (reduce_avg_allreduce_patch_xpu) -- no other vendor in this plugin has any monkeypatches. The generic "apply every patch" name and loop implied a cross-vendor aggregator like register_all_platforms()/ register_all_engines(), which genuinely do need to register every vendor up front since verl-core's registries look classes up by name after the fact. Patches don't share that constraint: they only ever matter to the one platform that already got selected, so each platform's own __init__ calling its own patch module directly is both simpler and more honest about what's actually happening than routing through a same-package wrapper that only ever had one real implementation behind it. verl_hardware_plugin/patches/__init__.py is now a plain package docstring pointing at reduce_avg_allreduce_patch_xpu, with no code. Updated the wiring test to mock the real target (reduce_avg_allreduce_patch_xpu.apply) instead of the removed wrapper. 75 passed.
_patched_all_reduce only checked op != AVG and async_op -- it never checked which backend the target group actually uses. Once applied, it silently intercepted op=AVG for every process group in the process, not just xccl ones: a gloo group in the same process (e.g. a CPU-only Ray actor's coordination group alongside a GPU worker's xccl group) would get routed through SUM+divide too, even though gloo/nccl handle AVG natively and never needed the workaround. Added dist.get_backend(group) != "xccl" to the short-circuit condition so non-xccl groups fall through to the original, untouched. Short-circuit evaluation means only the actual substitution path needs get_backend mocked in tests -- the passthrough tests (non-AVG op, async_op=True) never reach it, since op != AVG or async_op already short-circuits first. Added a test for a gloo-backed group with op=AVG to confirm it now passes through unpatched. 76 passed.
Per kahlun's review-thread investigation on verl-project/verl#7917 (measured on real 4xB60 hardware, not reasoned from source): xccl does not uniformly lack ReduceOp.AVG. oneCCL implements it on its SYCL-kernel execution path but not on its scheduler path; path selection is internal to oneCCL and isn't capability-aware, so an AVG request can abort mid-collective ("average operation is not supported for the scheduler path") rather than reliably succeed or reliably fail. Fix tracked for oneCCL 2022.2 / torch 2.15, not yet available on the stack this plugin targets. Also note the separate, narrower double-division bug on very small messages (intel/torch-xpu-ops#3020) is fixed on that same stack and is not what either the FSDP2 engine override or this patch works around -- easy to conflate the two since both are filed against xccl's AVG support. The blanket "xccl does not support ReduceOp.AVG" phrasing this replaces was accurate enough to justify the workaround but not accurate about why, and was written before this investigation existed. Same mechanism, same correctness -- corrected reasoning only. platform_xpu.py has the same blanket phrasing but predates both this branch and #22; left alone here since fixing it isn't part of this PR's diff. 76 passed.
kahlun
marked this pull request as ready for review
September 25, 2026 03:36
kahlun
requested review from
heavyrain-lzy and
physics31415926
as code owners
September 25, 2026 03:36
Collaborator
Author
|
@wuxibin89 @physics31415926 plugin-only ReduceOp.AVG patch for XPU/xccl, following the direction confirmed in #26 (no core changes). One open design question is called out in the PR description if you want to weigh in on it specifically; otherwise it should be good to merge as-is. |
…tches/__init__.py
…tdated platform subpackage references
physics31415926
approved these changes
Sep 30, 2026
physics31415926
pushed a commit
that referenced
this pull request
Oct 13, 2026
## Summary Adds Intel VTune (ITT) profiling support for Intel XPU, plus the XPU user guide that fills the stub `docs/accelerators/xpu/README.md`. After the rework described below, this PR implements exactly **one** `PlatformBase` hook — `profiler_markers()` — and does everything else from the plugin side: - `PlatformXPU.profiler_markers()` → ITT range markers, so verl core can emit trace ranges without knowing about ITT or XPU. - `VtuneProfiler(DistProfiler)`, selected by `profiler.tool: vtune`, registered by a plugin-side monkeypatch over `DistProfiler.__init__` (`verl_hardware_plugin/accelerators/xpu/profilers/register_vtune.py`) — no core hook. ## What changed since this PR was opened Two rounds of narrowing, both driven by the ruling on [#26](#26) (2026-09-23) that new `PlatformBase` hooks are reserved for capabilities that genuinely can't be done from the plugin: 1. **`is_reduce_avg_supported()` dropped** — the xccl `ReduceOp.AVG` gap doesn't meet that bar. Its plugin-only replacement landed as [#32](#32) (merged): a monkeypatch over `torch.distributed.all_reduce`, scoped to xccl groups. 2. **`attention_utils_module()` and `dist_profiler_cls()` dropped** (2026-10-08, commit `439503c`), following the narrowed hook surface in the rework of [verl-project/verl#7917](verl-project/verl#7917): - `attention_utils_module()`: nothing is needed from the plugin. verl core routes every backend without a `flash_attn` build through its own pure-PyTorch `attention_padding_utils` (the former `npu_flash_attn_utils`, renamed device-neutral) — the same `bert_padding` port this hook pointed at. - `dist_profiler_cls()`: it added a second dispatch mechanism alongside core's hardcoded if/elif, so `VtuneProfiler` is now claimed by the `register_vtune.py` monkeypatch instead. The patch is double-gated — applied from `PlatformXPU.__init__`, not at import time, and behind a live `torch.xpu.is_available()` check, because verl's platform auto-detection instantiates every registered platform to probe it. - `profiler_markers()` is kept: core's module-level markers are imported by the trainer at module scope, so there is no plugin-side seam for them. `verl_hardware_plugin/accelerators/xpu/engines/fsdp_xpu.py` is untouched by this PR. ## Motivation Add in profiling of step annotation for intel gpu ## Changes - `verl_hardware_plugin/accelerators/xpu/platform_xpu.py`: add `profiler_markers()`; apply the VTune registration patch from `__init__` behind a live-device check. - `verl_hardware_plugin/accelerators/xpu/profilers/itt_profile_xpu.py` (new): ITT range markers (`mark_start_range`/`mark_end_range`/`mark_annotate`/`marked_timer`) and `VtuneProfiler(DistProfiler)`. - `verl_hardware_plugin/accelerators/xpu/profilers/register_vtune.py` (new): claims the `vtune` tool name by wrapping `DistProfiler.__init__`. - `verl_hardware_plugin/accelerators/xpu/profilers/__init__.py` (new): docstring note on registration. - `tests/test_plugin_registration.py` (new): hook + registration tests that run on a CPU-only host. - `docs/accelerators/xpu/{install_guidance,quick_start,profiling}.md` (new) and an updated `README.md`. ## verl-core dependency `profiler_markers()` only exists on verl-core builds that include #7917. Against stock `verl-project/verl:main` the plugin still installs and runs, but the hook has no base method to override, so ITT ranges aren't emitted; #7917 also lifts the `tool_config` allowlist in `engine_workers.py`, without which a `tool_config.vtune` entry is dropped. `VtuneProfiler` registration itself is pure monkeypatch and works either way. Use the pinned ref in `docker/intel_gpu/` for a known-good combination until #7917 merges. ## Testing - [x] `pytest tests/` — 199 passed on a CPU-only host (`torch 2.13.0+xpu`), including the new registration tests. Re-run after merging the accelerator reorganization (#41), which moved these modules to `accelerators/xpu/`. - [x] Smoke-checked on 1x Arc Pro B60 against a verl-core build *without* #7917, i.e. the degraded path described above: `PlatformXPU` selected (`xpu`/`intel`/`xccl`); ITT markers execute; `profiler.tool: vtune` gives `DistProfiler._impl = VtuneProfiler` with `start`/`step`/`stop` running, while `tool: torch` still resolves to core's own profiler; and with no #7917 the hook is absent, markers stay generic and the `tool_config` allowlist stays gated — a silent fallback, not an error. - [x] ITT emission is real on this stack, not a stub: `torch.profiler.itt.is_available()` is `True` and `torch._C._itt` exposes `rangePush`/`rangePop`/`mark`. **Not covered:** viewing the ranges in a VTune result. VTune attaches as an external collector, so `profiler_start`/`profiler_stop` are no-ops by design and there is no code path here that only a capture would exercise. It is also not runnable in the Intel GPU image: its oneAPI 2026.1 ships no `vtune` component and no `libittnotify`. Installing the collector is an image change, independent of this PR — written up in `docs/accelerators/xpu/profiling.md` (Prerequisites + Troubleshooting). ## Acceptance Baseline (for new hardware adaptation PRs) - [x] GRPO / PPO / GRPO+colocated-RM / SFT (`tests/special_intel_gpu/*.sh`) completed full training steps on B60 with this branch's platform changes live in the tree - [ ] `critic/rewards/mean` upward trend / NVIDIA-reference curve from `scripts/baseline_grpo_gsm8k.sh` specifically — **TODO: paste the SwanLab/log link, or re-run that script.** **SwanLab or training log link**: TODO ## Checklist - [x] Code follows the project's style and passes `pre-commit` checks - [x] Documentation updated - [x] No secrets or credentials included --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
askhat-g
pushed a commit
to askhat-g/verl-hardware-plugin
that referenced
this pull request
Nov 1, 2026
## Summary Adds Intel VTune (ITT) profiling support for Intel XPU, plus the XPU user guide that fills the stub `docs/accelerators/xpu/README.md`. After the rework described below, this PR implements exactly **one** `PlatformBase` hook — `profiler_markers()` — and does everything else from the plugin side: - `PlatformXPU.profiler_markers()` → ITT range markers, so verl core can emit trace ranges without knowing about ITT or XPU. - `VtuneProfiler(DistProfiler)`, selected by `profiler.tool: vtune`, registered by a plugin-side monkeypatch over `DistProfiler.__init__` (`verl_hardware_plugin/accelerators/xpu/profilers/register_vtune.py`) — no core hook. ## What changed since this PR was opened Two rounds of narrowing, both driven by the ruling on [verl-project#26](verl-project#26) (2026-09-23) that new `PlatformBase` hooks are reserved for capabilities that genuinely can't be done from the plugin: 1. **`is_reduce_avg_supported()` dropped** — the xccl `ReduceOp.AVG` gap doesn't meet that bar. Its plugin-only replacement landed as [verl-project#32](verl-project#32) (merged): a monkeypatch over `torch.distributed.all_reduce`, scoped to xccl groups. 2. **`attention_utils_module()` and `dist_profiler_cls()` dropped** (2026-10-08, commit `439503c`), following the narrowed hook surface in the rework of [verl-project/verl#7917](verl-project/verl#7917): - `attention_utils_module()`: nothing is needed from the plugin. verl core routes every backend without a `flash_attn` build through its own pure-PyTorch `attention_padding_utils` (the former `npu_flash_attn_utils`, renamed device-neutral) — the same `bert_padding` port this hook pointed at. - `dist_profiler_cls()`: it added a second dispatch mechanism alongside core's hardcoded if/elif, so `VtuneProfiler` is now claimed by the `register_vtune.py` monkeypatch instead. The patch is double-gated — applied from `PlatformXPU.__init__`, not at import time, and behind a live `torch.xpu.is_available()` check, because verl's platform auto-detection instantiates every registered platform to probe it. - `profiler_markers()` is kept: core's module-level markers are imported by the trainer at module scope, so there is no plugin-side seam for them. `verl_hardware_plugin/accelerators/xpu/engines/fsdp_xpu.py` is untouched by this PR. ## Motivation Add in profiling of step annotation for intel gpu ## Changes - `verl_hardware_plugin/accelerators/xpu/platform_xpu.py`: add `profiler_markers()`; apply the VTune registration patch from `__init__` behind a live-device check. - `verl_hardware_plugin/accelerators/xpu/profilers/itt_profile_xpu.py` (new): ITT range markers (`mark_start_range`/`mark_end_range`/`mark_annotate`/`marked_timer`) and `VtuneProfiler(DistProfiler)`. - `verl_hardware_plugin/accelerators/xpu/profilers/register_vtune.py` (new): claims the `vtune` tool name by wrapping `DistProfiler.__init__`. - `verl_hardware_plugin/accelerators/xpu/profilers/__init__.py` (new): docstring note on registration. - `tests/test_plugin_registration.py` (new): hook + registration tests that run on a CPU-only host. - `docs/accelerators/xpu/{install_guidance,quick_start,profiling}.md` (new) and an updated `README.md`. ## verl-core dependency `profiler_markers()` only exists on verl-core builds that include #7917. Against stock `verl-project/verl:main` the plugin still installs and runs, but the hook has no base method to override, so ITT ranges aren't emitted; #7917 also lifts the `tool_config` allowlist in `engine_workers.py`, without which a `tool_config.vtune` entry is dropped. `VtuneProfiler` registration itself is pure monkeypatch and works either way. Use the pinned ref in `docker/intel_gpu/` for a known-good combination until #7917 merges. ## Testing - [x] `pytest tests/` — 199 passed on a CPU-only host (`torch 2.13.0+xpu`), including the new registration tests. Re-run after merging the accelerator reorganization (verl-project#41), which moved these modules to `accelerators/xpu/`. - [x] Smoke-checked on 1x Arc Pro B60 against a verl-core build *without* #7917, i.e. the degraded path described above: `PlatformXPU` selected (`xpu`/`intel`/`xccl`); ITT markers execute; `profiler.tool: vtune` gives `DistProfiler._impl = VtuneProfiler` with `start`/`step`/`stop` running, while `tool: torch` still resolves to core's own profiler; and with no #7917 the hook is absent, markers stay generic and the `tool_config` allowlist stays gated — a silent fallback, not an error. - [x] ITT emission is real on this stack, not a stub: `torch.profiler.itt.is_available()` is `True` and `torch._C._itt` exposes `rangePush`/`rangePop`/`mark`. **Not covered:** viewing the ranges in a VTune result. VTune attaches as an external collector, so `profiler_start`/`profiler_stop` are no-ops by design and there is no code path here that only a capture would exercise. It is also not runnable in the Intel GPU image: its oneAPI 2026.1 ships no `vtune` component and no `libittnotify`. Installing the collector is an image change, independent of this PR — written up in `docs/accelerators/xpu/profiling.md` (Prerequisites + Troubleshooting). ## Acceptance Baseline (for new hardware adaptation PRs) - [x] GRPO / PPO / GRPO+colocated-RM / SFT (`tests/special_intel_gpu/*.sh`) completed full training steps on B60 with this branch's platform changes live in the tree - [ ] `critic/rewards/mean` upward trend / NVIDIA-reference curve from `scripts/baseline_grpo_gsm8k.sh` specifically — **TODO: paste the SwanLab/log link, or re-run that script.** **SwanLab or training log link**: TODO ## Checklist - [x] Code follows the project's style and passes `pre-commit` checks - [x] Documentation updated - [x] No secrets or credentials included --------- Co-authored-by: Claude Opus 5 <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.
Open question for reviewers, up front
reduce_avg_allreduce_patch.pypatchestorch.distributed.all_reducewhenop=AVG— the only mechanism available for verl-core's 3 rawdist.all_reduce(op=ReduceOp.AVG)call sites, since there's no per-site wrapper to hook into and this plugin doesn't own those call sites. It's scoped todist.get_backend(group) == "xccl", so a gloo/nccl group in the same process (e.g. a CPU-only Ray actor's coordination group alongside a GPU worker's xccl group) is untouched and keeps nativeAVG— this was originally unscoped (any group, any backend) and has been fixed to check the backend per call. What's left: anyone reading verl-core's source still can't see, from that source alone, that an xccl group'sReduceOp.AVGsilently becomes SUM+divide, for as long as the process runs (there's no narrower call-boundary available — see Changes below for why). That's a real design smell, not a clean win, and is the one piece here still worth a narrow core-hook ask if that's judged unacceptable — happy to split it into its own PR against #7917 if so.Summary
Plugin-side replacement for
is_reduce_avg_supported()— implemented with zeroverl-corechanges: no newPlatformBasehook, no dependency on verl-project/verl#7917.Motivation
verl-hardware-plugin#26 asked maintainers whether Intel XPU should extend
PlatformBaseinverl-core(the TPU precedent) or stay entirely inside this plugin via monkeypatch (the MLU precedent). The maintainer's answer (2026-09-23): default to the plugin, keep #7917 narrowed to only what truly can't be done from here.is_reduce_avg_supported/all_reduce_avghas just been dropped from #7917 and from #22 on that basis -- the underlying reduce_avg problem doesn't need a core hook to work around. (Correction from an earlier version of this PR: the reason isn't "xccl doesn't implementReduceOp.AVG" -- per this review-thread investigation on real 4xB60 hardware, oneCCL implementsAVGon its SYCL-kernel path but not its scheduler path, and path selection is internal and not capability-aware, so anAVGrequest can abort mid-collective rather than reliably succeed or fail. Fix tracked for oneCCL 2022.2 / torch 2.15. Same mechanism below, corrected reasoning.) This PR is the plugin-side replacement.attention_utils_module()and the profiler hooks passed the maintainer's bar and stay asPlatformBasehooks — implemented for XPU in #22, which this PR does not touch or duplicate. (An earlier draft of this branch also monkeypatched attention as a "how far can pure monkeypatch go" comparison; dropped once it was clear the hook was staying and a plugin-only alternative for it served no purpose.)Changes
verl_hardware_plugin/engines/fsdp_xpu.py: extend the existing (non-hook, non-patch)initialize()override to callset_force_sum_reduction_for_comms(True)on the FSDP2 root and every individually-wrapped transformer layer, not just the root — eachfully_shard()'d module has independent FSDP state. This is ordinary method-override behavior on the plugin's ownEngineRegistry-registered engine, not a monkeypatch, so it's robust regardless of import order. Also fixes an unrelatedself.model→self.moduleattribute bug in the same function (FSDPEngineWithLMHead/WithValueHeadexpose the wrapped model asself.module, neverself.model) — [XPU] feat(xpu): add VTune (ITT) profiler backend #22 had picked up the same fix independently since it lives in the same lines; dropped from [XPU] feat(xpu): add VTune (ITT) profiler backend #22 in favor of this PR's superset version (root + per-layer, vs. root-only).verl_hardware_plugin/patches/reduce_avg_allreduce_patch(new): monkeypatchestorch.distributed.all_reduce(op=AVG)→SUM+ manual divide, scoped toxcclprocess groups (dist.get_backend(group) == "xccl"), for the three remaining rawdist.all_reduce(op=ReduceOp.AVG)call sites in verl-core (sft_trainer.py,engine_workers.py,profiler/performance.py::reduce_timing). See the open question above.async_op=Truecall sites are intentionally left unpatched (falls through to original behavior) rather than risk returning a wrong result before the collective completes.verl_hardware_plugin/patches/__init__.py(new): plain package docstring, no code — holdsreduce_avg_allreduce_patchas the one patch module. No genericapply_all()aggregator: it had exactly one caller and one module, so it wasn't earning its keep (see the platform_xpu.py bullet below).verl_hardware_plugin/platforms/platform_xpu.py:PlatformXPU.__init__callsreduce_avg_allreduce_patch.apply()directly. Deliberately not called from the sharedverl_hardware_plugin/__init__.py(that file is common to every vendor this plugin supports) —PlatformXPU()is only constructed onceverl.plugin.platform.platform_manager._create_platform()has actually selected"intel"as the platform for this process. Calling it from the shared top-level__init__.pyinstead would fire on any host wheretorch.xpumerely happens to be importable, even if a different platform ends up selected for the run — e.g. a mixed host withVERL_PLATFORM=nvidiaexplicitly set would still get its process-wideall_reducesemantics changed for no reason. (Two earlier drafts of this PR had this wired the wrong way, then routed through an unnecessary same-packageapply_all()wrapper — both fixed.)Testing
pytest tests/ -vpasses (76 passed), including new coverage:PlatformXPU()instantiation triggersreduce_avg_allreduce_patch.apply(); the shared plugin__init__.pyno longer binds any patch call directly (regression guard against re-introducing the wrong wiring).reduce_avg_allreduce_patch:op=AVGon anxcclgroup →SUM+ divide by world size;op=AVGon a non-xcclgroup (e.g.gloo) passes through untouched; other ops pass through unchanged;async_op=True+AVGfalls through unpatched; no-op when XPU unavailable; idempotent (callingapply()twice doesn't double-wrap).What's new here is the method-override framing
reduce_avg_allreduce_patch.py's actual collective behavior is unit-testedAcceptance Baseline (for new hardware adaptation PRs)
scripts/baseline_grpo_gsm8k.shon target hardware (8 devices)critic/rewards/meanshows clear upward trend in first 100 stepsChecklist
pre-commitchecksdocs/design/file; this repo has no precedent for keeping RFC/experiment-verdict docs in the merged tree