Repository navigation
Conversation
save_generator raised KeyError from inside its loop on an unexpected tensor
name, abandoning the generator. Its own comment says why that is not allowed:
the ranks that do not write sit in `for _ in generator: pass` to drive their
side of the export collectives. The writing rank leaving mid-stream blocks
them until the process-group timeout, so an export that should fail with a
KeyError on one rank hangs the whole job instead.
The distributed path had the same raise, and there every rank both produces
and consumes the generator. It also already carries the machinery for this:
local_export_error is gathered across ranks and raised afterwards, under a
comment asking for exactly this ("so all ranks raise consistently (avoids
hangs on the trailing barriers)"), and the message it raises claims the ranks
drained the generator. The duplicate-key branch in the same loop records
instead of raising; the unexpected-key branch now does the same.
Both keep writing nothing past the first offender, as raising on it did, and
both raise the same error once the generator is dry. strict=False is
untouched, and so is every call that passes it, including the training
checkpoint path.
Signed-off-by: Dmitry Voropaev <dy.voropaev@gmail.com>
This branch has not been deployed
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.
A strict export that hits an unexpected tensor name hangs the job instead of failing it.
save_generatorraised from inside its loop:Its own comment twelve lines above says why that is not ours to do:
Those ranks are inside
for _ in generator: pass. When rank 0 leaves the generator mid-stream, they stay blocked in the gather for the tensor rank 0 never asked for, until the process-group timeout.save_hf_weightsis where a user reaches this, its default isstrict=True, and its docstring says "This method is collective and must be called by all ranks".Measured on
53681c1withstate.pyloaded on its own, a two-key shard and a generator that records what it was asked for:model.secondis never pulled. With this change the same probe reports['model.first', 'surprise.weight', 'model.second']and raises the sameKeyError.The distributed path had it too
_save_generator_distributedcarried the same mid-loop raise, and there it is worse: every rank both produces and consumes the generator, so any rank can be the one that walks away.That function already has the machinery for this, and says so.
local_export_erroris gathered across ranks and raised afterwards, under this comment:and the error it raises reads
"Checkpoint export failed after all ranks drained the tensor generator: ...", which the mid-loop raise made untrue. The duplicate-key branch in the same loop, eight lines down, already records intolocal_export_errorand continues rather than raising. The unexpected-key branch now does the same.Scope
Both paths keep writing nothing past the first offender, exactly as raising on it did, and both raise once the generator is dry.
strict=Falseis untouched. Every caller that passesstrict=Falseis untouched too, including the training checkpoint path incheckpointing.py, whose own comment makes the same point ("Other ranks drain the streaming export generator so TP/PP/EP collectives complete").Testing
Two cases in
tests/unit_tests/models/test_hf_pretrained_state.py, next to the existingsave_generatortests and using the same_write_safetensors_indexand_mock_single_rank_distributedhelpers: one for the single-writer path, one for the distributed one. Both assert the generator was pulled dry and that the error still arrives. Both fail onmainand pass here, and I checked two control cases (a complete shard still saves,strict=Falsestill warns and saves) which pass either way. Notorch.distributedprocess group is needed.I could not run the repository's suite:
tests/unit_tests/conftest.pyimportsmegatron.core, which is not installable here, andmegatron/bridge/__init__pulls in the diffusion bridges, which need it too. So the runs above loadstate.pystandalone withimportlib, which is the real class and the real method, and I replicated the two new test bodies verbatim against it.ruff0.9.9 check and format are clean on both files.Same reporter as #6410, different file, no overlap.