feat(trainer): AsyncDiffusionTrainer for disaggregated async diffusion RL#192
Open
zzhuoxin1508 wants to merge 4 commits into
Open
feat(trainer): AsyncDiffusionTrainer for disaggregated async diffusion RL#192zzhuoxin1508 wants to merge 4 commits into
zzhuoxin1508 wants to merge 4 commits into
Conversation
…usion RL Diffusion sibling of AsyncARTrainer: subclasses DiffusionTrainer(layout=separate) to reuse the two-slab build + NCCLWeightSync handshake, and overlays the async rollout buffer loop (non-blocking generate, reap-time reward scoring off the train critical path, buffer of scored GRPO groups, train consumes the freshest batch). Knobs: max_inflight (overlap depth), buffer_max_staleness (0=on-policy). Adds unirl/trainer/async_diffusion.py, unirl/train_async_diffusion.py, and examples/diffusion/sd3/sd3_vllmomni_async.yaml. Purely additive.
…segment transfer, add BAGEL async recipe, drop SD3 async recipe
4f6c53a to
e35bd9c
Compare
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
AsyncDiffusionTrainer— the pure-DiT async RL trainer. Diffusion sibling ofAsyncARTrainer: training and rollout on disjoint GPU slabs, generation overlapped with training, reward scored off the train critical path, weights pushed cross-slab. The synchronous diffusion trainer is unchanged — purely additive (3 new files).Motivation: the synchronous diffusion path runs
generate → reward → trainin series each step, so generation + reward sit on the train critical path. Async overlaps them behind the train step.The key mechanism — reap-before-launch (what makes the overlap actually fast)
The buffer loop reaps (and cross-slab-transfers the completed generation's trajectory segment) BEFORE launching the next generation. That transfer runs on the rollout worker as an NCCL send; if a fresh generation were already queued on that worker (launch-first), the send blocks behind it — measured ~150s/rollout on BAGEL, even though the send itself is only ~3–8s. Reaping first gives the transfer an idle-worker window (~7–8s), then the next generation overlaps the caller's train step.
This requires
max_inflight=1: a second in-flight generation co-tenants the same rollout workers and reintroduces the stall. On shared rollout workers generations serialize anyway, somax_inflight=1costs no throughput while enabling the contention-free transfer + overlap. (This is also why plainvllm sync-separatenever hit the stall — it never runs a generation concurrently with the transfer.)What's added (3 files, purely additive)
unirl/trainer/async_diffusion.py—AsyncDiffusionTrainer(DiffusionTrainer). Reuseslayout="separate"two-slab build +_connect_separateNCCL handshake +_build_req/_drop_decoded/evaluate/ checkpoint + FlowGRPOstack.train_track. Overlays the async buffer loop (mirrorsAsyncARTrainer, engine/modality-agnostic): non-blocking_generate_async, reap-before-launch_next_batch,_reap_ready → _score_into_buffer(reward at reap time),_RolloutBufferof scored GRPO groups with freshness/staleness eviction,_drain_allquiesce before every weight sync.unirl/train_async_diffusion.py— Hydra entry (sibling oftrain_diffusion.py).examples/diffusion/bagel/bagel_vllmomni_async.yaml— BAGEL-7B-MoT async recipe (max_inflight=1,weight_sync_interval=4,buffer_max_staleness=0).Knobs:
max_inflight(must be 1, see above);weight_sync_interval(>1 required for overlap — interval=1 drains every step);buffer_max_staleness(0 = on-policy, ratio≈1; >0 = buffer survives weight syncs, off-policy continuous buffer).Validation (BAGEL-7B-MoT FlowGRPO, PickScore, 4 train + 4 rollout on 8×H20, batch=16 × 16 samples/prompt)
ratio = 1.0000throughout, reward grows, no crash / OOM.inflight=1 stale=0 interval=4inflight=1 stale=2 interval=4staleness=2eliminates the per-window cold sync-boundary rollout (276s → 110s) → ~148s avg, matching vllm colocate at 1.85×; ratio stays 1.0 (old_logp_source=rolloutanchors π_old to the emitted logp, so staleness moves gradient freshness, not the ratio).ProcessGroupNCCL(TCPStore)mechanismlocalizeuses, solocalizestays ~8s cross-node — the fix holds multi-node.Notes / risk
vllm_omni**enablement fixes not includedAsyncARTrainer(engine/modality-agnostic); a shared mixin is a natural follow-up refactor.Test Plan
--cfg jobcompose passesstaleness=0vsstaleness=2comparison; cross-node IB transfer validatedstaleness=2(off-policy drift check) — follow-up