feat(sc): train path — StalenessSampler + _train_pump rewrite#3220
Conversation
|
/ok to test bfb9075 |
bfb9075 to
f7a69a3
Compare
a1d41bf to
6580a91
Compare
f929aa0 to
48184ad
Compare
6580a91 to
283ba7f
Compare
terrykong
left a comment
There was a problem hiding this comment.
Reviewed in two passes with independent 5-agent teams (RL expert, test author, bug scanner, comment reviewer, devil's advocate); every finding was independently re-verified before staging, and the whole set was re-checked against the rebased head 283ba7f and against the upstack PRs (#3266/#3267) — findings resolved by the rebase or upstack (vllm marker, restored fast-lane tests, TaskGroup dispatch restructure, set_weight_version wiring, package __init__.py) were dropped rather than left as noise. Solid refactor overall — the sampler unit tests are thorough, the extracted helpers are byte-faithful moves of the originals, and the deleted nemo_rl/algorithms/staleness_sampler.py leaves zero dangling importers. 👍
One stack-aware note worth calling out: #3266 comments out the _sync_weights drain loop, which removes the invariant that keeps the evict-vs-commit race unreachable — that strengthens the case for the evict-skips-unready fix suggested on staleness_sampler.py.
Note: some comments below were staged against pre-rebase commit 6580a91 and may show as "outdated" threads — all were re-verified to still apply at 283ba7f.
CI: the last /ok to test bfb9075 predates the rebases, so head 283ba7f has no gated CI runs. Could you re-trigger with /ok to test 283ba7f3f8c366484a2d2ef1d142f15c7793010a? The mcore e2e (test_train_pump) couldn't be verified locally, so CI is the verification path for it.
pre-commit run --all-files passes on the branch, and the new source files (async_utils/staleness_sampler.py, single_controller_utils/utils.py) are in pyrefly.toml project-includes.
Generated by Claude Code
ac394aa to
d3188b2
Compare
Split the monolithic StalenessSampler into a PromptGroupSampler interface (admit/select/evict + is_on_policy/required_buffer_capacity) with one named policy per behavior (WindowedSampler / WeightFifoSampler / InOrderSampler), selected via a discriminated-union config or a module:ClassName FQN. admit() moves the rollout-pump dispatch gate + target_step stamping into the sampler so the pump follows the selected algorithm; InOrderSampler keys evict on target_step so evict/select agree by construction. Legacy knobs still work via sampler_from_legacy_knobs(); StalenessSampler kept as a compat facade. DRAFT / design demonstration for the #3220 sampler discussion. Not merged; not run locally (no compatible env). Signed-off-by: Terry Kong <terryk@nvidia.com>
Replace the monolithic StalenessSampler (five mode-encoding flags, three disjoint select branches, a shared evict fitting only two of the modes) with a PromptGroupSampler interface — admit/select/evict + is_on_policy / required_buffer_capacity — and one named policy per behavior: WindowedSampler / WeightFifoSampler / InOrderSampler. The sampler is selected by a pydantic discriminated-union config (name = windowed|weight_fifo|in_order|custom) or a module:ClassName FQN, so invalid knob combinations are unrepresentable and there are no cross-field validations in __init__. admit() moves the rollout-pump dispatch gate + target_step stamping into the sampler (the pump follows whichever policy is selected); InOrderSampler keys evict on target_step so evict/select agree by construction. No legacy-knob path: over_sampling / force_in_order / batch_selection_strategy / max_weight_staleness_versions and warn_if_staleness_window_below_minibatches are removed; the actor no longer owns _max_rollout_version. test_staleness_sampler (monolith) is replaced by test_sampler_interface. DRAFT / design demonstration for the #3220 sampler discussion. Not merged; not run locally (no compatible env). Signed-off-by: Terry Kong <terryk@nvidia.com>
) (#3316) Signed-off-by: Terry Kong <terryk@nvidia.com>
) (#3316) Signed-off-by: Terry Kong <terryk@nvidia.com>
f1589da to
4d0fa4e
Compare
|
/ok to test 4d0fa4e |
Signed-off-by: Yuki Huang <yukih@nvidia.com>
…wire StalenessSampler init Signed-off-by: Yuki Huang <yukih@nvidia.com>
Signed-off-by: Yuki Huang <yukih@nvidia.com>
Signed-off-by: Yuki Huang <yukih@nvidia.com>
Signed-off-by: Yuki Huang <yukih@nvidia.com>
…ighbours Signed-off-by: Yuki Huang <yukih@nvidia.com>
Signed-off-by: Yuki Huang <yukih@nvidia.com>
…p attrs Signed-off-by: Yuki Huang <yukih@nvidia.com>
…s init arg Signed-off-by: Yuki Huang <yukih@nvidia.com>
…window Signed-off-by: Yuki Huang <yukih@nvidia.com>
Signed-off-by: ruit <ruit@nvidia.com>
Signed-off-by: ruit <ruit@nvidia.com>
Signed-off-by: ruit <ruit@nvidia.com>
) (#3316) Signed-off-by: Terry Kong <terryk@nvidia.com>
Signed-off-by: ruit <ruit@nvidia.com>
Signed-off-by: ruit <ruit@nvidia.com>
4d0fa4e to
e6f3d76
Compare
|
/ok to test e6f3d76 |
saumishr
left a comment
There was a problem hiding this comment.
Seems the PR is merged. Most of my comments can be addressed as a follow up
|
|
||
|
|
||
| @runtime_checkable | ||
| class PromptGroupSampler(Protocol): |
There was a problem hiding this comment.
nit Lets keep the interfaces and concrete implementations in their own folders for better maintainability.
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 |
There was a problem hiding this comment.
We should probably name this as rl_controller. Single Controller term we have been using to mostly communicate the design choice of having a single controller doing all of the orchestration. Please feel free to do that in a follow up PR so that this one doesn't get blocked.
| """Shared machinery for the built-in policies. | ||
|
|
||
| Owns the monotonic dispatch counter (the batch index formerly tracked as | ||
| ``SingleControllerActor._max_rollout_version``) and the common |
There was a problem hiding this comment.
This doc needs to be updated? We seem to have removed _max_rollout_version?
| @@ -0,0 +1,455 @@ | |||
| # Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. | |||
Part 2/4 of the #2819 split. See #2819 (reference) or #3267 (4/4) for the full code and context. Stack on #3219.
#3219 (1/4) -> #3220 (2/4) -> #3266 (3/4) -> #3267 (4/4)
Summary
Train-side refactor of the SC (Single Controller) async-GRPO path — swaps the trainer's data source from
dp_client.claim_metato the newTQReplayBuffervia a filter-onlyStalenessSampler.StalenessSampler(nemo_rl/algorithms/async_utils/staleness_sampler.py): filter-only prompt-group selector over aTQReplayBuffer. Supportsmax_staleness_versions,sample_freshest_first,strict_weight_fifo, andforce_in_order(matches legacy async_grpo target_weight semantics). Replaces the old top-levelstaleness_sampler.py(deleted).SingleControllerActor._train_pump: rewritten tosampler.evict → sampler.select → _advantage_stage → TQPolicy split API (begin_train_step / train_microbatches_from_meta / finish_train_step) → dp_client.clear_samples. Drops orphaned pre-refactor helpers (_claim_available_meta,_claim_required_fields,_evict_stale_claimed,_flush_incomplete_groups) and their leftover config fields (consumer_task_name,claim_required_fields,max_claim_groups) + init attrs (_claimed_meta,_step_consumed_sample_ids).single_controller_utils/utils.py: extracted SC helpers (aggregate_step_metrics,reduce_advantage_pump_metrics,fields_for_put,squeeze_trailing_unit_dim,tensor_field) — pulls pure functions out ofsingle_controller.pyto keep it focused on pump orchestration.test_staleness_sampler; newtest_train_pump(real-MegatronTQPolicyend-to-end for_train_pump); shared_dp_fakesmodule (TQ data-plane fakes reused across pump tests);test_rollout_pumpre-homed onto_dp_fakes.Note: The production GRPO entrypoint (
run_grpo) becomes end-to-end runnable only after PR#3 lands the driver-side setup + entrypoint wiring. The newtest_train_pumpalready exercises SC end-to-end via a real Megatron TQPolicy on a tiny llama with the "simple" TQ backend.Known Missing Features (Tracked in #2625)
prev_logprobs_required/reference_logprobs_requiredgating is provisional.