perf(checkpoint): bound quantized DCP load memory - #3619
Draft
yuhezhang-ai wants to merge 3 commits into
Draft
Conversation
Signed-off-by: Yuhe Zhang <yuhez@nvidia.com>
Signed-off-by: Yuhe Zhang <yuhez@nvidia.com>
Signed-off-by: Yuhe Zhang <yuhez@nvidia.com>
3 tasks
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.
What this changes
This PR makes FP8 checkpoint conversion use a small part of the model at a time instead of keeping temporary tensors for the complete checkpoint alive at once.
The parent PR (#3616) already chooses DCP according to whether dequantization is actually needed. Two expensive cases remain for Mistral3/Devstral FP8 checkpoints:
This PR adds an optional adapter hook for checkpoints that require dtype or layout conversion:
Ordinary adapters do not implement the hook and keep their existing loading path.
The Mistral3 adapter groups at most eight text-decoder layers per part. It supports both the causal-LM layout and the untied full-VLM layout used by
mistralai/Devstral-Small-2-24B-Instruct-2512. In the VLM layout, the vision encoder and multimodal projector load directly into their final model weights rather than becoming additional temporary copies.FP32 master-weight configurations use the same bounded path. The model weights already have FP32 storage when loading begins, so each FP8 checkpoint part is converted directly into those FP32 destinations. The later FSDP mixed-precision policy can still use BF16 for compute.
Safety boundaries
The new path is considered only when all of the following are true:
The Mistral3 implementation additionally requires a complete decoder, BF16 or FP32 final weights, and the supported per-tensor FP8 checkpoint format. Pipeline-parallel ranks that own only part of the decoder and tied VLM checkpoints keep their existing fallback. Unsupported adapters and dtypes are unchanged.
The shared loader rejects missing checkpoint tensors, repeated checkpoint requests, repeated model destinations, and incomplete model coverage instead of allowing a partial load.
Measured results
Devstral 123B, TP=8 + LoRA
These runs used the same official
mistralai/Devstral-2-123B-Instruct-2512checkpoint, staged image, TP=8 + LoRA setup, and one-token forward pass.162960551629565516296372The final path reduces peak allocated GPU memory by 41.51 GiB/rank (57.7%). Model-load time changes by +1.08 seconds (1.2%), so the 123B result is a memory/OOM improvement with loading speed preserved, not a speed claim.
The final run used 12 DCP parts; its largest temporary part was 1.29 GiB/rank. It completed with 1,852 sharded parameters, trainable LoRA weights, and finite logits.
Devstral Small 2 24B VLM, one H100
This is the full
Mistral3ForConditionalGenerationVLM checkpoint, including its vision encoder and multimodal projector. The repository recipe uses text-only SQuAD data and normally runs in CI on one multi-GPU node; this benchmark deliberately used one GPU to exercise the path that previously built the complete checkpoint in CPU memory.Both measurements used the same checkpoint files after download. The comparison uses the fastest observed full-CPU run, making the speed comparison conservative.
1630121216301550For this real single-GPU VLM case, the new path is 3.9x faster. Peak CPU/process memory falls by 61.29 GiB, and peak CPU + GPU memory falls by 57.15 GiB (51.4%). GPU memory increases by 4.14 GiB because one bounded FP8 decoder group is temporarily present alongside the BF16 model; that allocation is released before the next group.
The loader read the 24.02 GB checkpoint in 12.65 seconds, including 12.55 seconds of storage reads and 0.02 seconds of FP8 conversion. The final one-token forward produced finite logits.
CPU/process and GPU memory were sampled together on a discrete-memory H100 system. Their sum is useful for estimating total loading pressure, but it is not a direct DGX Spark unified-memory measurement.
Validation
162963721630155016295582; every reconstructed parameter matched, including 16 real DTensor shards, and the forward was finitegit diff --check: passedAddresses the Devstral FP8 loading-memory case discussed in #2114.