feat: run:ai gpu_direct model loading with quantization-aware device maps - #635
Open
khaiwang wants to merge 5 commits into
Open
feat: run:ai gpu_direct model loading with quantization-aware device maps#635khaiwang wants to merge 5 commits into
khaiwang wants to merge 5 commits into
Conversation
…ice maps Add run:ai SafetensorsStreamer as the default loading backend for LanguageModel, with automatic fallback to from_pretrained when runai-model-streamer is not installed. Key features: - gpu_direct mode: copies tensors directly from Run:AI buffer to target GPU during streaming, making HF's _materialize_copy().to() a no-op - Quantization-aware _resolve_device_map: creates HfQuantizer and runs preprocess_model on the meta model so compute_module_sizes sees correct quantized parameter shapes (fixes 4x memory overestimate for MXFP4/GPTQ) - Thread-safe shard cache with per-tensor notification for pipelining disk I/O with GPU transfers across HF worker threads - CUDA expandable_segments enabled automatically to prevent fragmentation Benchmarks (cold cache, 8x A100-80GB PCIe): - Qwen3-30B-A3B (57 GB bf16): gpu_direct 2.4x faster than HF - gpt-oss-120b (61 GB MXFP4): gpu_direct 2.4x faster than HF - gpt-oss-20b (13 GB MXFP4, 1 GPU): gpu_direct 1.9x faster than HF Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Include benchmark_loading.py (hf vs gpu_direct configs) and README with architecture diagram, usage examples, and benchmark results across dense (Qwen3-8B), MoE (Qwen3-30B-A3B), and MXFP4 quantized (gpt-oss-120b) models. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
RunAI's DistributedStreamer auto-activates when torch.distributed is initialized (required by tp_plan), conflicting with the NCCL process group that transformers' TP creates. Detect tp_plan in _load and route to from_pretrained, which handles TP sharding natively (torch.narrow per rank during weight loading). Tested: torchrun --nproc_per_node=2 with Qwen3-8B tp_plan="auto" produces correct output with ~9 GB/rank (half of 15.3 GB model). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
RunAI's DistributedStreamer runs find_local_ranks() on every stream_files() call when torch.distributed is initialized. This creates a second NCCL communicator that conflicts with the existing TP process group, causing "Duplicate GPU detected" errors. Detect tp_plan in _load and route to from_pretrained, which handles TP sharding natively (torch.narrow per rank during weight loading). Tested: torchrun --nproc_per_node=2 with Qwen3-8B tp_plan="auto" produces correct output with ~9 GB/rank (half of 15.3 GB model). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Single-node TP with mmap shares OS page cache across ranks (1× read), while run:ai CPU-clone reads N× the data independently (measured 2× slower for Qwen3-8B on 2 GPUs). Also adds ValueError fallback for repos without .safetensors files and avoids passing device_map with tp_plan (mutually exclusive in from_pretrained). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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
LanguageModel, with silent fallback tofrom_pretrainedwhenrunai-model-streameris not installed — zero behavior change for existing users
.to(device)a no-op_resolve_device_map: createsHfQuantizerand runspreprocess_modelon the meta model before computing the device map, socompute_module_sizessees correct quantized parameter shapes. Without this, MXFP4/GPTQ models get 4× memory overestimates, causing unnecessary CPU offloading on tight GPU configs
benchmark_loading.py) and documentation (README.md)Benchmark Results (cold cache, 8× A100-80GB PCIe)
How it works
The Run:AI streamer uses N concurrent C++ pthreads for disk I/O (no GIL contention). The loader resolves
device_mapupfront, then copies each tensor to its target GPU as it arrives from the streamer. HF's_materialize_copy().to()becomes a device/dtype no-op. The streamer's background reads overlap naturally with the blocking
.to(cuda)calls.Usage
Files changed
src/nnsight/modeling/loader.pyRunAIShardCache,LazyRunAITensor,build_lazy_state_dictsrc/nnsight/modeling/transformers.py_loaddispatch,_resolve_device_mapwith quantizer,_load_streamedtests/performance/loading/benchmark_loading.pytests/performance/loading/README.mdTest plan
pytest tests/test_tiny.py --device cpu— 18/18 passrunai-model-streamerinstalled (usesfrom_pretrained)