Stream safetensors checkpoints into models - #411
Conversation
Signed-off-by: Gangzheng Tong <gtong@nvidia.com>
Greptile SummaryThis PR adds file-backed safetensors loading and direct tensor-by-tensor streaming into materialized models, then enables the bounded-memory path for LingBot World presets.
Confidence Score: 4/5The dependency constraint must be aligned with the new safetensors API before merging, otherwise valid installations can fail during model initialization. The streaming path calls Files Needing Attention: flashdreams/flashdreams/core/checkpoint/load.py and flashdreams/pyproject.toml Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[WAN transformer initialization] --> B{stream_checkpoint enabled?}
B -- No --> C[Materialize complete state dict]
C --> D[Module.load_state_dict]
B -- Yes --> E{Local or cached safetensors available?}
E -- No --> C
E -- Yes --> F[Open safetensors mmap]
F --> G[Validate keys and shapes]
G --> H[Copy one tensor at a time]
H --> I[Periodically evict checkpoint pages]
D --> J[Run post-load parameter updates]
I --> J
Reviews (1): Last reviewed commit: "Stream safetensors checkpoints into mode..." | Re-trigger Greptile |
| logger.warning(f"Could not evict checkpoint page cache for {path}: {exc}") | ||
|
|
||
| try: | ||
| with safe_open(path, framework="pt", device="cpu", backend="mmap") as source: |
There was a problem hiding this comment.
Unsupported safetensors loader keyword
When an installation resolves safetensors 0.4 through 0.7 as permitted by the package metadata, this call passes an unsupported backend keyword, causing model initialization to raise TypeError for streamed LingBot and other direct-to-model checkpoint loads.
| with safe_open(path, framework="pt", device="cpu", backend="mmap") as source: | |
| with safe_open(path, framework="pt", device="cpu") as source: |
Knowledge Base Used: Core Engine (flashdreams/flashdreams/core/)
|
/ok to test b0c0d2f |
ArielG-NV
left a comment
There was a problem hiding this comment.
1 suggestion
1 question
| """Pre-load state-dict remap (e.g. Self-Forcing's | ||
| ``generator_ema.model.…`` layout).""" | ||
|
|
||
| stream_checkpoint: bool = False |
There was a problem hiding this comment.
If safetensors are available (can be automatically detected from a checkpoint file afaik), shouldn't we by default always load them?
| in_dim=16 + 4 + 16, | ||
| ), | ||
| checkpoint_path=LINGBOT_WORLD_V1_CHECKPOINT_PATH, | ||
| stream_checkpoint=True, |
There was a problem hiding this comment.
We likely want this config option for all demos. Unsure if we should make this change now or if this change will be something we implement during a larger refactor.
There was a problem hiding this comment.
For smaller model or system with large RAM, this option is not helpful and will add some overhead when loading.
I'm testing the overhead to see if the difference matters or not. Will enable by default if not.
Summary
materialized model instead of first constructing a complete in-memory state
dict
periodically release consumed checkpoint pages from the Linux page cache
stream_checkpointsetting to the WAN transformer config andenable it for every LingBot World v1 and v2 preset
LingBot configuration defaults
Motivation
Loading a large model previously required the destination model and the entire
checkpoint state dict to be resident at the same time. LingBot World uses a 14B
parameter transformer, so BF16 weights alone are roughly 28 GB before accounting
for the rest of the pipeline, allocator overhead, filesystem page cache, and
other runtime memory.
That transient duplication can exhaust system memory on machines with 64 GB of
host RAM. It is also a problem on systems with 128 GB of unified memory, such as
DGX Spark, because CPU checkpoint pages and GPU model allocations compete for
the same physical memory pool. The resulting memory pressure can cause an OOM,
heavy reclaim, or a load failure before inference starts even when the final
materialized model fits.
This change keeps checkpoint loading bounded by copying one tensor at a time
from the memory-mapped safetensors file into the destination model. It avoids a
second model-sized state dict and advises the OS to discard already consumed
checkpoint pages in 512 MiB intervals.
Conceptually, peak checkpoint-loading residency changes from approximately:
to:
Behavior and compatibility
load_checkpoint(..., model=model)can resolve alocal or cached safetensors file.
base configuration.
opt in with
stream_checkpoint=True.state dict, preserving the public API.
resolved to a local file continue through the existing loader path.
state_dict_transform; the WAN loaderraises a clear error if both options are requested.
or steady-state generation performance after loading completes.
Validation
ci_cputests that reject the old whole-file byte-loading path forlocal safetensors.
not called and that the destination weights match the checkpoint.
enable streaming checkpoint loading.
Limitations and follow-ups
materializing path on its first load.
producing that cache for the first time still uses the existing merge path.
interface rather than the current whole-state-dict callback.