Repository navigation
[XPU] add in scheduler.avg with patch, not dependent on verl-core #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
physics31415926
merged 11 commits into
verl-project:main
from
kahlun:experiment/xpu-monkeypatch-reduce-avg-attention
Sep 30, 2026
Merged
Changes from 9 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
f0f6dba
experiment: XPU reduce_avg + attention support, pure monkeypatch
kahlun de6f66a
refactor: narrow this branch to reduce_avg only, drop the attention p…
kahlun ff00a01
fix(xpu): apply the reduce_avg patch on platform selection, not import
kahlun a7669ab
refactor: drop the patches.apply_all() indirection, call the module d…
kahlun 08fb6a9
fix(xpu): scope the reduce_avg patch to xccl process groups only
kahlun 4b90cec
docs(xpu): correct the reason for the reduce_avg workaround
kahlun 07aa5df
fix(tests): simplify mock patching in test_platform_xpu_init_applies_…
kahlun b9c4b7d
feat(xpu): move the monkey patch of the avg of xpu to folder
kahlun cac78f9
fix(patches): resolve pytest update import paths for reduce_avg_allre…
kahlun dd71d54
docs(patches): clarify the application context of monkeypatches in pa…
kahlun ff5416e
docs(patches): streamline documentation in __init__.py by removing ou…
kahlun File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| # Copyright (c) 2026 BAAI. All rights reserved. | ||
| # Licensed under the Apache License, Version 2.0. | ||
|
|
||
| """Plugin-side monkeypatches, one module per capability, applied only from | ||
| the platform class that needs them -- not from this package's `__init__.py` | ||
| and not from this plugin's shared top-level `verl_hardware_plugin/__init__.py`. | ||
|
|
||
| `PlatformXXX()` is only constructed once `verl.plugin.platform. | ||
| platform_manager._create_platform()` has actually selected that platform for | ||
| the process (see `PlatformXPU.__init__` in `platforms/platform_xpu.py`). | ||
| Applying a patch from a shared location instead would fire on any host where | ||
| the corresponding hardware/SDK merely happens to be importable, regardless of | ||
| which platform verl actually selects for the run. | ||
|
|
||
| Currently contains one platform subpackage: | ||
|
|
||
| - `xpu.reduce_avg_allreduce_patch`: Intel XPU's `is_reduce_avg_supported` | ||
| replacement. See its own docstring for what it does and why it's a | ||
| monkeypatch rather than a `PlatformBase` hook (verl-hardware-plugin#26). | ||
| """ | ||
89 changes: 89 additions & 0 deletions
89
verl_hardware_plugin/patches/xpu/reduce_avg_allreduce_patch.py
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| # Copyright (c) 2026 BAAI. All rights reserved. | ||
| # Licensed under the Apache License, Version 2.0. | ||
|
|
||
| """Monkeypatch torch.distributed.all_reduce(op=AVG) -> SUM + manual divide, | ||
| scoped to xccl process groups, for Intel XPU. | ||
|
|
||
| Why this is needed: Intel's oneCCL (xccl) implements ReduceOp.AVG on its | ||
| SYCL-kernel execution path, but not on its scheduler path. Which path a | ||
| given collective takes is selected internally by oneCCL and isn't | ||
| capability-aware, so a caller can't tell in advance whether an AVG request | ||
| will succeed or abort mid-collective (`average operation is not supported | ||
| for the scheduler path`). Forcing sum-based reduction + a manual divide is | ||
| the only way to guarantee correctness until that dispatch becomes | ||
| capability-aware -- fix tracked for oneCCL 2022.2 / torch 2.15, not yet | ||
| available on the stack this plugin targets. (A separate, narrower | ||
| double-division bug on very small messages, intel/torch-xpu-ops#3020, is | ||
| fixed on that same stack and is not what this patch works around.) | ||
|
|
||
| This is the one patch in this package worth calling "doable, but with a real | ||
| design smell" rather than "clean": | ||
|
|
||
| - verl/workers/engine_workers.py, verl/trainer/sft_trainer.py, and | ||
| verl/utils/profiler/performance.py::reduce_timing each call | ||
| `torch.distributed.all_reduce(x, op=ReduceOp.AVG, ...)` as a literal inline | ||
| expression -- there is no per-site wrapper or dispatch object to patch, the | ||
| way there is for attention padding. | ||
| - Patching `torch.distributed.all_reduce` itself is robust to import order | ||
| (every call site does `dist.all_reduce(...)`, an attribute lookup on the | ||
| `torch.distributed` module performed at call time, not at each file's own | ||
| import time), so this does take effect regardless of load order. | ||
| - The cost: this still intercepts a public torch API process-wide -- once | ||
| applied, every `dist.all_reduce(op=AVG)` call in the process is routed | ||
| through this wrapper, XPU-related or not. It is scoped to xccl groups via | ||
| `dist.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 native `AVG` -- but anyone | ||
| reading verl-core's source still can't see, from that source alone, that | ||
| an xccl group's `ReduceOp.AVG` silently becomes SUM+divide. That is a | ||
| legitimate argument for fixing this in verl-core instead | ||
| (verl-project/verl#7917's `is_reduce_avg_supported()` hook covers exactly | ||
| these 3 call sites) -- this patch exists to show it is *possible* without | ||
| core changes, not to claim it is the better design. | ||
|
|
||
| async_op=True is intentionally unsupported: correctly dividing the result | ||
| requires the collective to have already completed, which async_op explicitly | ||
| defers. Call sites using async_op=True with op=AVG fall through to the | ||
| original behavior -- subject to the same oneCCL path-selection risk this | ||
| patch exists to avoid -- rather than silently producing a wrong answer with | ||
| no error. | ||
| """ | ||
|
|
||
| import logging | ||
| import os | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
| logger.setLevel(os.getenv("VERL_LOGGING_LEVEL", "WARN")) | ||
|
|
||
| _applied = False | ||
|
|
||
|
|
||
| def _xpu_available() -> bool: | ||
| import torch | ||
|
|
||
| return hasattr(torch, "xpu") and torch.xpu.is_available() | ||
|
|
||
|
|
||
| def apply() -> None: | ||
| global _applied | ||
| if _applied: | ||
| return | ||
| if not _xpu_available(): | ||
| return | ||
|
|
||
| import torch.distributed as dist | ||
|
|
||
| original_all_reduce = dist.all_reduce | ||
|
|
||
| def _patched_all_reduce(tensor, op=dist.ReduceOp.SUM, group=None, async_op=False): | ||
| if op != dist.ReduceOp.AVG or async_op or dist.get_backend(group) != "xccl": | ||
| return original_all_reduce(tensor, op=op, group=group, async_op=async_op) | ||
|
|
||
| world_size = dist.get_world_size(group=group) | ||
| result = original_all_reduce(tensor, op=dist.ReduceOp.SUM, group=group, async_op=False) | ||
| tensor.div_(world_size) | ||
| return result | ||
|
|
||
| dist.all_reduce = _patched_all_reduce | ||
| _applied = True | ||
| logger.info("[verl_hardware_plugin] Patched torch.distributed.all_reduce(op=AVG) for xccl process groups") |
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
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.