Repository navigation
Unify HF snapshot and checkpoint writing - #3198
Conversation
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.
Tip: disable this comment in your organization's Code Review settings.
9f6ab17 to
de50878
Compare
dc2bd67 to
fb2c208
Compare
de50878 to
570de0d
Compare
fb2c208 to
6595faf
Compare
570de0d to
bb5e5de
Compare
6595faf to
59ebf9b
Compare
bb5e5de to
2b578d0
Compare
59ebf9b to
b25633c
Compare
2b578d0 to
4ebb542
Compare
b25633c to
7f106a2
Compare
4ebb542 to
1080c7f
Compare
7f106a2 to
d94d93b
Compare
|
@claude review |
There was a problem hiding this comment.
approve - the same way used in multi-lora.
But agent catch some issue. So I list below.
-
Reviewed d94d93b47088; reproduced against base using CPU/Gloo with stubbed model conversion, not GPU E2E.
-
Regression: Failed exports leave tmp_step*; eval cleanup deletes only final paths. Two failed exports left four files versus zero on base.
-
Regression: LoRA saving now uses rank-0-only directory creation/publication, breaking node-local checkpoints on other nodes. Base succeeds; head reports a missing directory.
-
Existing issue remains: With empty HF exports, nested save phases mismatch across ranks; peers time out. Coordinate validation before entering adapter saving.
| try: | ||
| if should_log: | ||
| logger.info(f"Saving model in HuggingFace format to {path}") | ||
| write_checkpoint_dir(path, write_shards) |
There was a problem hiding this comment.
🔴 save_hf_model now stages writes in a hidden _tmp_<name> sibling of the final path and only renames it in on success; on failure the tmp dir is never removed. export_hf calls this with raise_on_error=True, and eval_dispatch.py's failure handler only shutil.rmtree(hf_dir, ...) on the final path (a no-op since it never existed) — not the new _tmp_step_<id> sibling — so every failed --eval-hf-dir export now leaks a full snapshot dir on (recommended tmpfs) disk, unbounded by eval_keep_snapshots/eval_max_in_flight. Fix: write_checkpoint_dir must remove its tmp dir on failure (or every caller doing its own cleanup, like eval_dispatch, must also remove <parent>/_tmp_<name>).
Extended reasoning...
eval_dispatch._export -> actor_model.export_hf(rollout_id, hf_dir) -> save_hf_model(path=hf_dir, raise_on_error=True) -> write_checkpoint_dir(path, write_shards) at hf_export.py:169 builds tmp_dir = hf_dir.parent/f'tmp{hf_dir.name}', mkdirs it, then runs write_shards. If write_shards raises (e.g. the bridge-mapping RuntimeError at hf_export.py:155, or any export error on any rank), the exception propagates straight out of write_checkpoint_dir with no finally/cleanup — publish_dir, the only code that renames or discards tmp_dir, is never reached, so tmp_dir is orphaned on disk. The exception surfaces in eval_dispatch.py at the except Exception as e: around line 51, whose handler does shutil.rmtree(hf_dir, ignore_errors=True); since hf_dir (the final path) was never created, this removes nothing, and _tmp_step_<rollout_id> stays. Because each eval point uses a unique step_<rollout_id> name, no later export ever revisits that tmp path to clean it up (write_checkpoint_dir only removes a stale tmp_dir at the start of a new attempt targeting the same final path), so every failed…
Verification: normal. Real disk leak regression introduced on the eval-export failure path. write_checkpoint_dir (checkpoint_io.py:31-64) stages writes in tmp_dir = final_dir.parent/f"tmp{final_dir.name}" (line 37) and only renames onto final_dir in publish_dir (line 60), run last (line 64). If write_shards raises, run_checkpoint_phase re-raises (line 27-28) and propagates out with no try/finally to…
yushengsu-thu
left a comment
There was a problem hiding this comment.
Reviewed d94d93b47088; reproduced against base using CPU/Gloo with stubbed model conversion, not GPU E2E.
- Regression: Failed exports leave
_tmp_step_*; eval cleanup deletes only final paths. Two failed exports left four files versus zero on base. - Regression: LoRA saving now uses rank-0-only directory creation/publication, breaking node-local checkpoints on other nodes. Base succeeds; head reports a missing directory.
- Existing issue remains: With empty HF exports, nested save phases mismatch across ranks; peers time out. Coordinate validation before entering adapter saving.
1080c7f to
31b97cf
Compare
d94d93b to
98b3c57
Compare
31b97cf to
a491dd9
Compare
2ca1558 to
fef299e
Compare
…ails" This reverts commit f7793d7.
Use the default sglang-miles dependency after the SGLang 0.5.20 migration. The old PR-body pin selected dataclass ServerArgs while the tests require msgspec Struct. Trigger a fresh CI event to read the corrected PR body.
Keep the shared SnapshotPublisher/checkpoint writer instead of the old save barriers; it already coordinates writes over Gloo. Preserve main strict native adapter validation and deterministic gradient dtype ordering, together with the native optimizer restoration result.
| if checkpoint_dir.exists(): | ||
| if not overwrite: | ||
| raise FileExistsError(f"checkpoint {checkpoint_dir} already exists") | ||
| shutil.rmtree(checkpoint_dir) |
There was a problem hiding this comment.
rmtree fails on symlink checkpoints written by the current write_checkpoint_dir; unlink symlinks (and dangling ones) before mkdir.
There was a problem hiding this comment.
because the symlink is just added in multi-lora, I think there will not be users now, so we can do this for simplicity
| torch.save(training_state, checkpoint_dir / f"training_state_rank{global_rank}.pt") | ||
|
|
||
| return str(save_path) | ||
| write_checkpoint_dir(save_dir, write_shards) |
There was a problem hiding this comment.
[P2] Node-local LoRA saves fail on nonzero nodes; create checkpoint directories on each node.
There was a problem hiding this comment.
given full checkpoint is written to only rank 0, I think this unification is ok
Keep actor-owned snapshot publishing and best-effort HF adapter export. Adopt the moved HF/LoRA utilities and derive adapter targets from exported names. Preserve main raw-mode native checkpoints and their rank-sharded config without creating an unused publisher, plus sampling-support replay and native optimizer restoration.
ci-sglang-pr: #40242
Single-LoRA saves and full-model HF exports share
SnapshotPublisherfor HF files and onewrite_checkpoint_dir()for directory handling. Overwriting removes the old checkpoint before writing the new one; failed overwrites leave no usable checkpoint. Readers that overlap later saves use distinct snapshot paths.Changes
megatron_rank_shardedadapter config, without gathering HF weights or creating a publisher solely for native saves. Bridge-mode checkpoints and sampler snapshots derive HF adapter targets from their exported parameter names.--no-load-optimretain the existing master refresh.WeightUpdaterandSnapshotPublishercomponents. Ordinary training uses the updater, multi-LoRA uses the publisher, and training with snapshot export can use both. Each export reads current model weights through the actor-owned publisher.SnapshotPublisher.write_adapter()writes HF adapter files;write_model()streams raw full-model safetensors shards and writes their index and config/tokenizer files. All ranks participate in weight conversion; rank 0 writes these files. Bridge retains its existing full-model/merged-LoRA export implementation.META.jsonor.completewhen requested. The result exchange also waits for writers, so no additional barrier or phase framework is needed. Failed writes are cleaned after writers finish. Ordinary directories replace symlink publication and retained hidden versions.--save-hf, appendstep_{rollout_id}to paths without a rollout ID format field and log the adjusted path. Existing templates, including{rollout_id:06d}, stay unchanged. Independent eval exports, shared-engine eval, and ordinary saves keep their existing paths. Eval retains its existing snapshot retention policy and removes consumed directories directly.adapter/subdirectory. Give each fully-async eval E2E case its own temporary snapshot directory because CI containers share host IPC.Megatron's native full-model checkpoint and async-save protocol are unchanged. This does not recover process death, broken collectives, or failures inside Bridge/Megatron internals. Cleanup requires writers to have stopped; failed cleanup can leave incomplete files. Tinker checkpoint errors still terminate the trainer cell. Reusing a path while a reader remains active is unsupported, including repeated exports of the same step across runs.
Validation
39ca293ff6, all five CPU jobs and pre-commit passed. Six NVIDIA GPU jobs failed with the stale Megatron73b54618f7e5override: five could not import Bridge becausemla_qk_norm_configwas absent; Kimi K3 failed the initial weight comparison on threerouted_expert_normtensors because that backend predates Kimi primitives. Both are present in merged Megatron Support move-based offloading in FSDP backend #102/Try to synchronize after FSDP wakeup #94. Removed the override to use the defaultmiles-main(currently651dd728e3c1); fresh CI is pending. No production code or tests changed.test_lora_fields_roundtrip: Miles now emits full HF target paths, while the default SGLang branch still rejects them as CLI choices. Added the same SGLang #40242 dependency used by merged Miles Unify LoRA target selection with HF model layouts #3318; its current head is2068f5ed9115. Verified at39ca293ff6in CI run 35932539087: all four stage-a CPU shards, stage-b CPU, and pre-commit passed. The originaltest_lora_fields_roundtripexecuted and passed; its shard reports 3453 passed, 5 skipped, and 7 xfailed. CI used merge ref7b8d5885c960, SGLang2068f5ed9115, and Megatron73b54618f7e5. NVIDIA GPU validation is still pending. No production code or test assertions were changed for this dependency fix.7d1d15b1ccinto0755b073f6, preserving the HF/LoRA namespace move, HF target selection, raw-mode saves, and sampling-support replay. Local pre-commit and diff checks pass. Two-process CPU/Gloo probes cover native/HF/sampler success and failure, raw saves with zero HF gathers, target names from exported tensors, and per-slot rank/alpha. Component probes cover all nine updater/publisher configurations and reuse across exports; twenty Inkling restore A/B cases still pass. Conversion/framework setup are simulated; tensors, files, safetensors, and Gloo collectives are real. No new repository tests or GPU runs for this merge; hosted CI pending.b1cbb43dc2, pre-commit and diff checks pass. A two-process CPU/Gloo A/B probe against97c3eecab2injects a rank-0 HF adapter write error: the base fails both ranks and removes the checkpoint; the fix returns successfully on both ranks and preserves all four native/training-state files, including exact optimizer tensors and scheduler state. Rank-1 native write errors and sampler HF export errors still fail both ranks and clean up. Repository function bodies, tensors, files, safetensors, and Gloo collectives are real; model conversion and optimizer objects are simulated. No repository tests or GPU runs were added for this fix.8e3c71390a: all four stage-a shards and stage-b are green (run). CI tested merge refbe7f0665af0awith SGLang5a8da8cc3fc1and Megatron73b54618f7e5. Removed the obsolete SGLang pin from the PR body after the 0.5.20 migration; both previously failing ServerArgs tests now execute successfully.90ea0b3a8e; retained its strict native adapter validation and deterministic gradient dtype ordering. Localpre-commit run --all-filesandgit diff --checkpassed on97c3eecab2. Formatting changes are isolated in a separate commit and AST-equivalent. Hosted CI for this head is pending.1.0010000467to1.0) before the Inkling guard and exact preservation afterward. Twenty before/after cases cover native resume, step zero, legacy shards, HF-only loading, omitted optimizer state,--no-load-optim, and skipped base loading. Tensors and checkpoint files were real; the base-model loader, optimizer, and Inkling tensor mapping were simulated. No new repository tests or GPU runs were added.0efaee7953: fully-async eval passedshared,fleet, andexternal, including step 0/1 HF exports in both dedicated eval modes. CI run passed CPU/pre-commit; NVIDIA jobs had 3 passes and 5 failures from the Bridge/Megatronmla_qk_norm_configimport incompatibility. This predates the final writer refactor; the final implementation has not been validated on GPUs.