feat(async): release rollout lanes during remote reward scoring - #362
Open
zzhuoxin1508 wants to merge 4 commits into
Open
feat(async): release rollout lanes during remote reward scoring#362zzhuoxin1508 wants to merge 4 commits into
zzhuoxin1508 wants to merge 4 commits into
Conversation
zzhuoxin1508
force-pushed
the
feat/driver-local-remote-reward
branch
from
August 12, 2026 08:09
f6a4b07 to
5853716
Compare
Collaborator
Author
zzhuoxin1508
marked this pull request as ready for review
August 13, 2026 06:45
zzhuoxin1508
requested review from
CjhHa1,
Ideny42,
KemingWu,
Zcchill,
celve,
haonan3,
heguangxin and
leviking98z-rgb
as code owners
August 13, 2026 06:45
…ward for BAGEL it2i
zzhuoxin1508
force-pushed
the
feat/driver-local-remote-reward
branch
from
August 21, 2026 06:59
620690d to
224a5bf
Compare
zzhuoxin1508
force-pushed
the
feat/driver-local-remote-reward
branch
from
August 21, 2026 08:48
8007164 to
9caf6d8
Compare
Make capacity release and driver reward placement explicit, ensure the remote recipe exercises the async path, and remove unrelated reward implementations and deployment workarounds.
zzhuoxin1508
force-pushed
the
feat/driver-local-remote-reward
branch
from
August 21, 2026 09:17
9caf6d8 to
63b2913
Compare
Keep one directly runnable async remote recipe without inherited managed-reward configuration, and satisfy the repository's one-line docstring policy.
…spended dead path, and drop unrelated device_pool change
Ideny42
reviewed
Aug 29, 2026
Ideny42
left a comment
Collaborator
There was a problem hiding this comment.
The current W&B timing metrics do not accurately describe the async execution path. install_phase_timing() instruments train_step(), but AsyncDiffusionTrainer runs through _train_async_loop(), so phase metrics such as generate/reward/train time are not recorded. The remaining perf/step_time_s mixes collect wait, refill, advantage computation, and training, while excluding quiesce/weight sync. It therefore cannot show the actual rollout/reward/training latency or their overlap. Could we add async-specific timing metrics for capacity release, reward completion, training, sync, and end-to-end round time?
Ideny42
approved these changes
Aug 30, 2026
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.


Summary
Two model-agnostic additions to the async RL rollout path:
1. Per-lane released-capacity state in
RolloutPool— the main change.Before, a rollout lane's capacity was freed only when its call fully resolved. Now a pending call may expose
is_capacity_released(): the instant generation finishes, the lane is released — moved from_runninginto a new_releasedstate — so it can admit the next prompt while the call keeps completing in the background. The unit only enters_completedonce fully done. This splits "generation finished" (frees the GPU lane) from "result ready" (joins the batch), so downstream work can overlap the next generation instead of holding the lane.2. A reward client that runs in the driver (
DriverRewardClient).A reward client hosted on the driver process (a thread pool), not on a GPU worker/slab. It sends generated media to a remote
RewardServiceover HTTP and exposes the samelaunch_nowait/ready/resultsurface as a GPUHandle, so the per-lane manager drives it uniformly.chain_rewardhooks it onto the released-capacity release point: generation done → stream to the remote reward → lane freed → the scored group joins the batch in reward-completion order. Opt-in viareward_client_on_driver: true; every training-node GPU then stays train+rollout while the reward model lives on its own node.Both are generic and default-off — they work for any diffusion/AR rollout and any remote reward model. Also adds
RemoteRewardBackend(HTTP client to the RewardService/scoregateway, with per-request identity/idempotency for safe retries under async concurrency) and an opt-in example recipe.Rebased onto current
mainafter #289 and #304 merged. The diff now contains only the waiting-queue and driver-local remote-reward layer.Related Issue
Builds on #289 and #304 (both merged).
Test Plan
Validated end-to-end with BAGEL-7B image-edit (it2i) as the policy and EditReward (MiMo-VL-7B) as the remote reward — the mechanism itself is model/reward agnostic. 2-node bring-up: a 1-GPU EditReward HTTP
RewardService(unirl-reward-service) plus 8-GPU async training via thebagel_it2i_vllmomni_async_remoterecipe (num_devices=8,reward_client_on_driver=true) wired byREWARD_SERVICE_URL. The streaming run advances at ~90 s/round with per-round reward scores logged and varying; lanes free at generation-done (_released) and reward scoring overlaps the next generation. See Performance below for the overlap ablation. Focused smoke tests for released-capacity dispatch and chained reward completion were run locally; the standalone BAGEL remote recipe also passes Hydra compose (not committed, per the repo tests/ policy #99/#267).Performance
Speed ablation on the same setup (BAGEL-7B it2i policy,
batch_size=8 × samples_per_prompt=8= 64 images/round, remote EditReward over HTTP, single 8×H20 node; steady-state s/round after warmup):Takeaways. The released-capacity overlap this PR enables is the dominant lever: turning it on (staleness
0 → 1) cuts −63 s/round (153 → 90) — the rollout slab generates round N+1 while the train slab trains round N.1 → 2adds nothing, sincemax_inflight=1already caps in-flight work at one round. With overlap on, the separate 4+4 async layout (90 s) beats colocate-8 run serially (106 / 128.5 s) even though each phase uses only half the GPUs — generation is fully hidden behind training. An independent second axis is the rollout engine: trainsidebs=1eager generation vsvllm_omnicosts +22.5 s/round on colocate (128.5 → 106).Compatibility / Risk
Opt-in:
reward_client_on_driverdefaults off; existing reward placement is unchanged when off. Requires a reachableRewardService(REWARD_SERVICE_URL).Reviewer Notes
Rebased onto current
mainafter #289/#304 merged; the diff is now limited to the waiting-queue and driver-local remote-reward changes.Checklist