Repository navigation
[OMNIML-6082] [15/21] Add the pieces of a distributed HF checkpoint writer - #2751
shengliangxu wants to merge 7 commits into
Conversation
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
8aef85d to
6994370
Compare
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## shengliangx/hfep-12a-keep-fused-fold #2751 +/- ##
========================================================================
+ Coverage 61.75% 61.83% +0.07%
========================================================================
Files 655 656 +1
Lines 73098 73327 +229
========================================================================
+ Hits 45144 45344 +200
- Misses 27954 27983 +29
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
/ok to test 6994370 |
6994370 to
5b2ee4a
Compare
|
/ok to test 5b2ee4a |
5b2ee4a to
f738cd0
Compare
f738cd0 to
812e4e1
Compare
|
/ok to test 812e4e1 |
812e4e1 to
6c1cb0e
Compare
6c1cb0e to
a8e0c27
Compare
a8e0c27 to
a3be04a
Compare
|
/ok to test 992b8f3 |
|
/ok to test ed900e5 |
|
/ok to test b3cb0f2 |
|
/ok to test fab7a67 |
|
/ok to test 3eec2a9 |
|
/ok to test 2d85f70 |
|
/ok to test 52fcfa8 |
|
/ok to test c6bf2af |
|
/ok to test 6b650ce |
|
/ok to test c274dc5 |
|
/ok to test c69cff5 |
|
/ok to test fa8c1e5 |
|
/ok to test e1e746f |
|
/ok to test 7095ff2 |
|
/ok to test 67caebe |
|
/ok to test b6d674b |
|
/ok to test 81aca54 |
|
/ok to test 918e6e6 |
|
/ok to test 2556c46 |
|
/ok to test 675a8e0 |
|
/ok to test b551cba |
Exporting an FSDP2 model gathers every shard to rank 0 first, so rank 0 needs host RAM for the whole model and the gather costs world x the bytes, and an expert-parallel model cannot go through that path at all. These are the pieces of a writer where every rank writes its own share instead (modelopt/torch/export/distributed_writer.py): - _materialize_owned gives each tensor exactly one owner rank and makes it whole there: replicated and plain values need no transport, and dim-0 shards travel point-to-point, batched and bucketed per peer -- one bucket per key deadlocked at 16 ranks. Placements it cannot assemble, and shards that do not tile the global shape, raise rather than risk a silently mis-assembled checkpoint. - _revert_whole_sd runs the reverse weight conversion on those whole tensors, which transformers' conversion ops need: they cannot express a placement. - _write_even_shards bin-packs each rank's set into even files numbered into one global range, writes them with safetensors, and unions the index on rank 0, failing on a name two ranks both wrote. A tensor over max_shard_size gets a file of its own, as in HF, and the rest still pack. The entry point that drives them follows. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
A rank whose shard write raised left the writer and met its peers in a different collective: they raised an unrelated error or, when the failure was rank 0's name-collision check or index write before the closing barrier, waited out the process group's timeout. The per-rank file counts, the shard writes and rank 0's index write now each run inside the failure-carrying all_reduce, so every rank raises with the failing rank's error, and every rank checks the union of the written names for a collision. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
_size_to_bytes is one table of a decimal and a binary unit, case and padding, bare numbers and the refusals, not a row per unit. _even_bins is one table of the file sizes it produces; the every-key-once test goes, since the shard writer's test fails when a tensor is dropped. The _materialize_owned refusals are one table: a dim-1 shard, a smaller or 2-D mesh, a padded chunk. The _is_full_world_shard0 accept/reject tests go with it, as the materialize test's sharded tensor and that table cover both answers. _nbytes keeps only its DTensor case, the revert fallback no longer pins its warning text, and the two pooled jobs use the shared bounded_collectives with plain asserts: the peer of a failing rank must get that rank's error. The local gloo_world_of_one goes for the conftest's. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
_write_even_shards created the export directory before its first collective, so a rank whose filesystem refused the mkdir raised alone while its peers waited in "shard counts" until the process-group timeout, against the function's own contract that every step a rank can fail alone runs inside all_reduce. Create it inside the "shard counts" all_reduce instead, which adds no collective. The one-rank failure test gains a "dir" case. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
_materialize_owned refused an unsupported placement before its metadata gather, and checked tiling against each rank's own view of the global shape. A rank whose view diverged (a packed-weight rewrap once re-inferred the global shape per rank) then raised alone while its peers waited in the gather or the point-to-point transport until the timeout. Gather every rank's placement verdict and view of the global shape in the one metadata collective, and decide every refusal from that data before anything moves, so all ranks raise. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Each rank of the no-gather writer reverses the conversion mapping on the tensors it owns. A merge needs its whole group, which the per-tensor ownership can spread over ranks, and a rank holding none of a group fails it. That rank kept its in-memory names while the others wrote hub names, so the checkpoint mixed the two. The ranks now agree on the outcome: if the reverse fails on any rank, every rank keeps the in-memory names, as the single-process export does on a failure. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
|
/ok to test dd1344d |
What does this PR do?
Type of change: New feature
Exporting an FSDP2 model gathers every shard to rank 0 first, so rank 0 needs host RAM for the whole model and the gather costs world x the bytes. An expert-parallel model cannot go through that path at all. These are the pieces of a writer where every rank writes its own share instead (
modelopt/torch/export/distributed_writer.py):_materialize_ownedgives each tensor exactly one owner rank and makes it whole there:Placements it cannot assemble, and shards that do not tile the global shape, raise rather than risk a silently mis-assembled checkpoint.
_revert_whole_sdruns the reverse weight conversion on those whole tensors, so they go out under the checkpoint's names. transformers' conversion ops cannot express a placement._write_even_shards:Failing together. The export directory's creation with the file counts, the shard writes and rank 0's index write each run inside the failure-carrying
all_reduce([4/21]), so one rank's failure raises on every rank with that rank's error rather than leaving the others in an unmatched collective.A tensor over
max_shard_sizegets a file of its own, as in HF, and the rest still pack.The entry point that drives them arrives in [16/21].
Usage
N/A: internal to the distributed export ([16/21]).
Testing
tests/unit/torch/export/test_distributed_writer.py, on CPU under gloo, drives each piece directly:bounded_collectives. Each drop is checked by mutation.Before your PR is "Ready for review"
CONTRIBUTING.md: N/AAdditional Information
Part 15 of 21 of expert-parallel PTQ for Hugging Face MoE models; merges after [14/21].
Summary by CodeRabbit