Skip to content

refactor weight processing in RL weight update - #28001

Merged
yueming-yuan merged 4 commits into
sglang-milesfrom
weight_update_refactor
Jun 25, 2026
Merged

yueming-yuan merged 4 commits into
sglang-milesfrom
weight_update_refactor

Conversation

@yueming-yuan

@yueming-yuan yueming-yuan commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

Refactors the online weight-update post-processing on the SGLang side. Training (miles) no longer drives the restore/quantize ordering via a 3-flag post_process_weights RPC. Instead the engine owns a weight-update session:

  • begin_weight_update — restores in-place-packed weights to a loadable state (no-op for schemes that don't repack, e.g. plain fp8). Sets _weight_update_in_progress.
  • update_weights_from_* — assert a session is open (catches silent misuse); record that model.load_weights() ran this session.
  • end_weight_update — quant finalize (process_weights_after_loading) on the full model, plus model.post_load_weights() only when load_weights was bypassed this session (i.e. P2P/RDMA). The engine decides this itself via _weight_update_loaded; no flag crosses the API.

post_process_weights (RPC + the restore/quantize/post_load boolean dispatcher) is deleted.

Why

  • The restore/quantize/post-load transforms depend on engine-side settings (kernel backend, hardware, quant scheme) — they belong on the engine, not the trainer.
  • A begin/end bracket gives "restore once / finalize once" naturally and works uniformly for tensor / broadcast / P2P (P2P has no per-bucket update RPC, so explicit begin/end is required).
  • The open-session assert turns a previously-silent misuse (updating weights without the surrounding prep) into a loud error.

Changes

  • io_struct.py: BeginWeightUpdate* / EndWeightUpdate* req/resp replace PostProcessWeights*.
  • model_loader/loader.py: extracted restore_weights_before_loading_all / process_weights_after_loading_all as free functions (single canonical definition, alongside the existing post-load helper); renamed _post_load_weightspost_load_weights.
  • scheduler / tp_worker / tokenizer_control_mixin / http_server / engine: begin/end wiring; removed post_process_weights.

Paired change

Requires the matching miles-side PR (begin/end calls replace post_process_weights).

Notes

  • post_load_weights is still embedded in model.load_weights() for tensor/broadcast (runs per-bucket); pulling it out so all transports run it once at end_weight_update is a deliberate follow-up. _weight_update_loaded is the seam for it.
  • Lint: isort + black applied to the changed files manually (full pre-commit suite not runnable in this partial checkout).

CI States

Latest PR Test (Base): ❌ Run #28138539341
Latest PR Test (Extra): 🚫 Run #28138539302

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@yueming-yuan
yueming-yuan force-pushed the weight_update_refactor branch from f0f0a14 to c556cb1 Compare June 12, 2026 05:33
yueming-yuan added a commit to radixark/miles that referenced this pull request Jun 12, 2026
Replaces the post_process_weights RPC calls with SGLang's new
begin_weight_update / end_weight_update session API. begin opens the
session (restore packed weights) right after pause/flush; end closes it
(quant finalize + post_load) before resuming generation.

Drops the int4-only restore conditional and the per-transport
post_load_weights flag -- the engine now decides post_load itself based
on whether model.load_weights ran this session (P2P bypasses it).

Requires the paired sglang change (sgl-project/sglang#28001).

Co-authored-by: Nan Jiang <59716405+nanjiangwill@users.noreply.github.com>
@yueming-yuan
yueming-yuan force-pushed the weight_update_refactor branch from c556cb1 to f9e4415 Compare June 12, 2026 05:46
@yueming-yuan yueming-yuan changed the title Replace post_process_weights with begin/end_weight_update session API refactor weight processing in RL weight update Jun 12, 2026
Comment thread python/sglang/srt/managers/tp_worker.py Outdated
restore_weight(self.model_runner.model, torch.device(self.device))
return True, "Success"

def end_weight_update(self, run_post_load: bool):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need run_post_load: bool? cuz i notice miles side just do end_weight_update(self.rollout_engines). also for correctness i think we need to do post_load_weights all the time?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

post_load_weight is coupled with model.load_weights(), so any update weight method triggering load_weight() has already do this.
This run_post_load method is used to support the p2p weight update, where load_weight() is not triggered, and the tensors are directly replaced by p2p.

def begin_weight_update(self, recv_req: BeginWeightUpdateReqInput):
"""Begin a new weight update session: restore packed weights to a loadable state."""
self._quiesce_for_weight_update()
success, message = self.tp_worker.begin_weight_update()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whether draft worker need begin weight update?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let me push some commit in this PR to fix...

Training no longer drives restore/quantize ordering. The engine opens a
weight-update session via begin_weight_update (restores in-place-packed
weights to a loadable state) and closes it via end_weight_update (quant
finalize on the full model, plus model.post_load_weights only when
load_weights was bypassed this session, e.g. P2P/RDMA). The engine tracks
the session itself; update_weights_from_* now assert a session is open to
avoid silent misuse.

- io_struct: BeginWeightUpdate/EndWeightUpdate req/resp (replaces PostProcessWeights)
- loader: extract restore_weight / postprocess_weight free functions;
  rename _post_load_weights -> post_load_weights
- scheduler/tp_worker/tokenizer_control/http_server/engine: begin/end wiring;
  remove post_process_weights and the 3-flag dispatcher

On v0.5.13 the scheduler weight-update logic lives in
SchedulerWeightUpdaterManager (scheduler_components/weight_updater.py), so
the session state + begin/end methods are hosted there.

Co-authored-by: Nan Jiang <59716405+nanjiangwill@users.noreply.github.com>
@yueming-yuan
yueming-yuan force-pushed the weight_update_refactor branch from fe5b459 to 33f9d0d Compare June 18, 2026 23:44
yueming-yuan and others added 3 commits June 18, 2026 19:33
…_refactor

# Conflicts:
#	python/sglang/srt/managers/scheduler_components/weight_updater.py
…28710)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@yueming-yuan
yueming-yuan merged commit 64b0059 into sglang-miles Jun 25, 2026
5 of 6 checks passed
@yueming-yuan
yueming-yuan deleted the weight_update_refactor branch June 25, 2026 00:26
nanjiangwill pushed a commit to nanjiangwill/sglang that referenced this pull request Jul 7, 2026
…sgl-project#18565, sgl-project#22663, sgl-project#28001, sgl-project#29675)

Combined weight-processing machinery, folding the general post-process
plumbing from the INT4 QAT work (sgl-project#18565), the P2P post_load_weights
extension (sgl-project#22663), the weight-processing refactor (sgl-project#28001), and the
pause-aware weight locking fix (sgl-project#29675) into its final form:

- Begin/EndWeightUpdate request chain: engine/http_server/
  tokenizer_control_mixin (pause-aware locking) -> scheduler ->
  weight_updater sessions with {target,draft,all} runner selectors
- loader.py: public post_load_weights, restore_weight/postprocess_weight
  via _apply_quant_method_hook (skips LoRA wrappers)
- model_runner begin/end_weight_update + receive_weights_from_distributed
- iter_runners() on tp_worker and all spec v2 workers (incl. port to
  DFlashWorkerV2; v1 dflash/frozen-kv workers no longer exist)
- CompressedTensorsFusedMoEMethod.restore_weights_before_loading dispatch
- weight_checker ComparableWeight refactor + weight_checker_comparator

Co-authored-by: JD-ETH <jaedon.guo@gmail.com>
Co-authored-by: maocheng23 <35615230+maocheng23@users.noreply.github.com>
yueming-yuan added a commit that referenced this pull request Jul 14, 2026
…sessions + spec-draft weight check (#18565, #22663, #28001, #29675, #27750)

Combined weight-processing machinery, folding the general post-process
plumbing from the INT4 QAT work (#18565), the P2P post_load_weights
extension (#22663), the weight-processing refactor (#28001), and the
pause-aware weight locking fix (#29675) into its final form, plus the
extension of the weight checker to speculative draft worker(s) (#27750):

- Begin/EndWeightUpdate request chain: engine/http_server/
  tokenizer_control_mixin (pause-aware locking) -> scheduler ->
  weight_updater sessions with {target,draft,all} runner selectors
- loader.py: public post_load_weights, restore_weight/postprocess_weight
  via _apply_quant_method_hook (skips LoRA wrappers)
- model_runner begin/end_weight_update + receive_weights_from_distributed
- iter_runners() on tp_worker and all spec v2 workers (incl. DFlashWorkerV2)
- CompressedTensorsFusedMoEMethod.restore_weights_before_loading dispatch
- weight checker: selector + skip_tensor_list + role-prefixed overall_checksum
  over get_model_runners(selector), replacing _get_draft_model_runner

Kept v0.5.15's upstreamed ComparableWeight weight_checker_comparator
(incl. the #29623 ue8m0 scale-unpack fix); adapted the weight_checker
caller to its public compare_weights/CHUNK_NUMEL API.

Co-authored-by: JD-ETH <jaedon.guo@gmail.com>
Co-authored-by: maocheng23 <35615230+maocheng23@users.noreply.github.com>
Co-authored-by: Jiajun Li <jiajun.li@radixark.ai>
yueming-yuan added a commit that referenced this pull request Jul 14, 2026
…sessions + spec-draft weight check (#18565, #22663, #28001, #29675, #27750)

Combined weight-processing machinery, folding the general post-process
plumbing from the INT4 QAT work (#18565), the P2P post_load_weights
extension (#22663), the weight-processing refactor (#28001), and the
pause-aware weight locking fix (#29675) into its final form, plus the
extension of the weight checker to speculative draft worker(s) (#27750):

- Begin/EndWeightUpdate request chain: engine/http_server/
  tokenizer_control_mixin (pause-aware locking) -> scheduler ->
  weight_updater sessions with {target,draft,all} runner selectors
- loader.py: public post_load_weights, restore_weight/postprocess_weight
  via _apply_quant_method_hook (skips LoRA wrappers)
- model_runner begin/end_weight_update + receive_weights_from_distributed
- iter_runners() on tp_worker and all spec v2 workers (incl. DFlashWorkerV2)
- CompressedTensorsFusedMoEMethod.restore_weights_before_loading dispatch
- weight checker: selector + skip_tensor_list + role-prefixed overall_checksum
  over get_model_runners(selector), replacing _get_draft_model_runner

Kept v0.5.15's upstreamed ComparableWeight weight_checker_comparator
(incl. the #29623 ue8m0 scale-unpack fix); adapted the weight_checker
caller to its public compare_weights/CHUNK_NUMEL API.

Co-authored-by: JD-ETH <jaedon.guo@gmail.com>
Co-authored-by: maocheng23 <35615230+maocheng23@users.noreply.github.com>
Co-authored-by: Jiajun Li <jiajun.li@radixark.ai>
yueming-yuan added a commit that referenced this pull request Jul 25, 2026
… for spec draft worker(s) (#27749, #28575, #18565, #22663, #28001, #29675, #27750)

Squash of the spec-draft distributed-update work and the weight-processing
session work: the latter rewrites iter_draft_runners()/get_model_runners() the
former introduces, so they cannot be applied independently.

  - Draft runners never join the update group, so the target receives the
    broadcast once and the weights are loaded into every selected runner.
  - Begin/EndWeightUpdate session chain: engine / http_server /
    tokenizer_control_mixin (pause-aware locking) -> scheduler ->
    SchedulerWeightUpdaterManager, with {target,draft,all} runner selectors.
  - loader.py: public post_load_weights plus restore_weight/postprocess_weight
    via _apply_quant_method_hook (skips LoRA wrappers).
  - weight checker: skip_tensor_list + role-prefixed overall_checksum over
    get_model_runners(selector), replacing _get_draft_model_runner.

Reimplemented onto v0.5.16, which had already extracted weight updating into
ModelRunner.weight_updater (WeightUpdater): the receive/load split lands there
as receive_weights_from_distributed() + load_weights() rather than on
ModelRunner, and the scheduler fan-out drives runner.weight_updater.*. The
worker-level update_weights_from_{distributed,tensor} entry points on
TpModelWorker / EAGLEWorkerV2 / NGRAMWorker are dropped: the scheduler now owns
the fan-out, and leaving them would be a second path that updates one runner
only. iter_runners() replaces the ad-hoc draft-runner discovery on every spec v2
worker (incl. DFlashWorkerV2). The unit test moves to test/registered/rl/, since
v0.5.16 retired test/srt/ from CI collection.

Co-authored-by: Yueming Yuan <yym022502@gmail.com>
Co-authored-by: JD-ETH <jaedon.guo@gmail.com>
Co-authored-by: maocheng23 <35615230+maocheng23@users.noreply.github.com>
Zhichenzzz pushed a commit that referenced this pull request Sep 19, 2026
… for spec draft worker(s) (#27749, #28575, #18565, #22663, #28001, #29675, #27750)

(cherry picked from commit 4290cf4)
(cherry picked from commit 3c0c432)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants