Repository navigation
fix(model-manager): stop float8 checkpoints pinning their file after load - #10194
Draft
Pfannkuchensack wants to merge 6 commits into
Draft
Pfannkuchensack wants to merge 6 commits into
Pfannkuchensack wants to merge 6 commits into
Conversation
Free the outgoing expert before the next one loads, so a swap no longer holds both. Stop fp32-kept tensors pinning whole fp32 shards in Diffusers folders. Read single files without mmap and reserve before the fold and cast.
…load Single-file loaders that widen float8 weights to bf16 left the tensors already in bf16 (norms, biases) as views of the safetensors mapping. Those views kept the whole file mapped for the model's lifetime, outside the RAM cache budget. Checkpoints whose weights include float8 are now read with safetensors' pread backend; files without float8 weights keep the mmap path. Working set after load, Windows, CPU, real loaders: Krea-2 fp8 36.8 -> 25.2 GB, Qwen-Image Edit fp8 65.3 -> 46.2 GB, Mistral fp8 50.5 -> 35.1 GB, FLUX.2 Klein 9B fp8 27.0 -> 19.2 GB. Weights are bit-identical.
# Conflicts: # invokeai/backend/model_manager/load/model_loaders/wan.py # tests/app/invocations/test_wan_expert_swapper.py # tests/backend/model_manager/load/test_wan_checkpoint_loader.py
Since invoke-ai#10185 a marked int8 file takes the int8 branch and stays int8, and an unmarked one is refused, so no int8 weight reaches the fold any more. The int8 branch reserves before its split and has its own reservation test.
# Conflicts: # invokeai/backend/model_manager/load/model_loaders/flux3.py # tests/backend/flux3/test_loaders.py
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.
Summary
Single-file loaders that widen float8 weights to bf16 kept the whole checkpoint file in memory for as long as the model stayed cached.
safetensors.torch.load_filemaps the file and every tensor is a slice of that mapping. The widened fp8 weights get new storage, but tensors already in the target dtype (norms, biases) stay views because.to(dtype)is a no-op for them, and those few views keep the entire mapping alive. The RAM cache does not count it.Checkpoints whose
.weighttensors include float8 are now read with safetensors'preadbackend, where each tensor owns its storage. Files without float8 weights (bf16, fp16, int8, pure nvfp4) keep the mmap path unchanged.fp8_scaled.py:safetensors_backend(path)andload_safetensors_checkpoint(path).safe_openreads.Working set after load (GB), real loaders, Windows, CPU only:
FLUX.2 Klein 9B load peak: 26.4 -> 19.3 GB.
Related Issues / Discussions
Follow-up to #10192, which fixed the same pin for Wan 2.2.
QA Instructions
Measurement: the real
ModelLoader._load_modelon CPU, reservations stubbed. Each run touches every parameter after the load and reads the process working set, then lists the mapped model-file regions that no parameter still uses.Before:
main. After: this branch.Weights: a hash over every state-dict tensor (name, dtype, shape, bytes) is identical before and after for all 9 fp8 files and both mixed nvfp4 files (Qwen3-VL 4B and 8B).
No-float8 controls are unchanged and still fully mapped: Krea-2 int8, FLUX.3 bf16, Anima-3.8B bf16.
Mixed nvfp4 Qwen3-VL 8B: 5.5 -> 4.9 GB, with 2.2 GB of file no longer held.
Kept fp8, where weights are not widened: same end state and bit-identical, but the file is read up front. Krea-2 load went from 0.1 s to 5 s.
Load time with the file already in the OS cache, interleaved, one warm-up plus 3 runs, median:
preadcopies what mmap only maps. A cold load from disk was not measured for this change. For fix(wan): keep system RAM within the model cache budget #10192,preadmatched mmap on a cold 19 GiB read (462 against 431 MiB/s).Tests: 3645 passed, 170 skipped. The run covered
tests/backend/model_manager/load,tests/backend/model_manager/configs,tests/test_model_manager,tests/test_calibrate_wan_vae_working_memory.py, andtests/backend/quantization,flux3,anima,qwen3_5,moss_image.uv lock --checkand Ruff are clean.New tests:
platform_independentAST guard fails if a loader that folds or casts fp8 goes back to rawload_file.Not run: Linux, macOS, ROCm, GPU generation, family E2E. No local single-file Ideogram 4 or ERNIE fp8 file, so those two sites are covered by unit tests only. A pure nvfp4 file could not be measured, because the local FLUX.3 nvfp4 file is not identified on
maineither.Review
Fixed during review:
Known limits:
preadreads one tensor. On a slow disk other Python threads stall for that tensor's read: 1.2 GB tensors exist in Mistral and Qwen3-VL. Multiple GPUs feel this most.load_default.pymakes for the file size before the load.preadsince fix(wan): keep system RAM within the model cache budget #10192.Checklist
What's Newcopy (if doing a release after this PR)Open in [code]smith · Need help on this PR? Tag
@codesmith-botwith what you need.