[Auto Sync] Update loader.py, weight_utils.py (20260213) (#18779)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Xiuyu Li <xiuyu@x.ai>
Co-authored-by: Cheng Wan <54331508+ch-wan@users.noreply.github.com>
This commit is contained in:
Lianmin Zheng
2026-02-13 12:22:50 -08:00
committed by GitHub
co-authored by github-actions[bot] Xiuyu Li Cheng Wan
parent 4c6afbeeaa
commit 008ea46af1
2 changed files with 68 additions and 47 deletions
+2 -2
View File
@@ -88,6 +88,7 @@ DEFAULT_GPU_MEMORY_FRACTION_FOR_CALIBRATION = (
) )
from sglang.srt.environ import envs from sglang.srt.environ import envs
from sglang.srt.model_loader.weight_utils import ( from sglang.srt.model_loader.weight_utils import (
buffered_multi_thread_safetensors_weights_iterator,
download_safetensors_index_file_from_hf, download_safetensors_index_file_from_hf,
download_weights_from_hf, download_weights_from_hf,
fastsafetensors_weights_iterator, fastsafetensors_weights_iterator,
@@ -99,7 +100,6 @@ from sglang.srt.model_loader.weight_utils import (
initialize_dummy_weights, initialize_dummy_weights,
maybe_add_mtp_safetensors, maybe_add_mtp_safetensors,
multi_thread_pt_weights_iterator, multi_thread_pt_weights_iterator,
multi_thread_safetensors_weights_iterator,
np_cache_weights_iterator, np_cache_weights_iterator,
pt_weights_iterator, pt_weights_iterator,
safetensors_weights_iterator, safetensors_weights_iterator,
@@ -508,7 +508,7 @@ class DefaultModelLoader(BaseModelLoader):
hf_weights_files, hf_weights_files,
) )
elif use_multithread: elif use_multithread:
weights_iterator = multi_thread_safetensors_weights_iterator( weights_iterator = buffered_multi_thread_safetensors_weights_iterator(
hf_weights_files, hf_weights_files,
max_workers=extra_config.get( max_workers=extra_config.get(
"num_threads", self.DEFAULT_NUM_THREADS "num_threads", self.DEFAULT_NUM_THREADS
+66 -45
View File
@@ -1,10 +1,12 @@
# Adapted from https://github.com/vllm-project/vllm/blob/v0.6.4.post1/vllm/model_executor/model_loader/weight_utils.py # Adapted from https://github.com/vllm-project/vllm/blob/v0.6.4.post1/vllm/model_executor/model_loader/weight_utils.py
"""Utilities for downloading and initializing model weights.""" """Utilities for downloading and initializing model weights."""
import collections
import concurrent.futures import concurrent.futures
import fnmatch import fnmatch
import glob import glob
import hashlib import hashlib
import itertools
import json import json
import logging import logging
import os import os
@@ -709,35 +711,11 @@ def np_cache_weights_iterator(
yield name, torch.from_numpy(param) yield name, torch.from_numpy(param)
def decrypt(fn, key):
raise NotImplementedError()
def safetensors_encrypted_weights_iterator(
hf_weights_files: List[str],
is_all_weights_sharded: bool = False,
decryption_key: Optional[str] = None,
):
raise NotImplementedError()
def safetensors_weights_iterator( def safetensors_weights_iterator(
hf_weights_files: List[str], hf_weights_files: List[str],
is_all_weights_sharded: bool = False,
decryption_key: Optional[str] = None,
disable_mmap: bool = False, disable_mmap: bool = False,
) -> Generator[Tuple[str, torch.Tensor], None, None]: ) -> Generator[Tuple[str, torch.Tensor], None, None]:
"""Iterate over the weights in the model safetensor files. """Iterate over the weights in the model safetensor files."""
If is_all_weights_sharded is True, it uses more optimize read by reading an
entire file instead of reading each tensor one by one.
"""
if decryption_key:
yield from safetensors_encrypted_weights_iterator(
hf_weights_files, is_all_weights_sharded, decryption_key
)
return
enable_tqdm = ( enable_tqdm = (
not torch.distributed.is_initialized() or torch.distributed.get_rank() == 0 not torch.distributed.is_initialized() or torch.distributed.get_rank() == 0
) )
@@ -751,8 +729,8 @@ def safetensors_weights_iterator(
if disable_mmap: if disable_mmap:
with open(st_file, "rb") as f: with open(st_file, "rb") as f:
result = safetensors.torch.load(f.read()) result = safetensors.torch.load(f.read())
for name, param in result.items(): for name in sorted(result.keys()):
yield name, param yield name, result[name]
else: else:
with safetensors.safe_open(st_file, framework="pt", device="cpu") as f: with safetensors.safe_open(st_file, framework="pt", device="cpu") as f:
for name in f.keys(): for name in f.keys():
@@ -816,25 +794,10 @@ def fastsafetensors_weights_iterator(
def multi_thread_safetensors_weights_iterator( def multi_thread_safetensors_weights_iterator(
hf_weights_files: List[str], hf_weights_files: List[str],
is_all_weights_sharded: bool = False, max_workers: int,
decryption_key: Optional[str] = None,
max_workers: int = 4,
disable_mmap: bool = False, disable_mmap: bool = False,
) -> Generator[Tuple[str, torch.Tensor], None, None]: ) -> Generator[Tuple[str, torch.Tensor], None, None]:
"""Multi-Thread iterate over the weights in the model safetensor files. """Multi-Thread iterate over the weights in the model safetensor files."""
If is_all_weights_sharded is True, it uses more optimize read by reading an
entire file instead of reading each tensor one by one.
"""
if decryption_key:
logger.warning(
"Multi-Thread loading is not working for encrypted safetensor weights."
)
yield from safetensors_encrypted_weights_iterator(
hf_weights_files, is_all_weights_sharded, decryption_key
)
return
enable_tqdm = ( enable_tqdm = (
not torch.distributed.is_initialized() or torch.distributed.get_rank() == 0 not torch.distributed.is_initialized() or torch.distributed.get_rank() == 0
) )
@@ -865,6 +828,64 @@ def multi_thread_safetensors_weights_iterator(
yield name, param yield name, param
def buffered_multi_thread_safetensors_weights_iterator(
hf_weights_files: List[str],
max_workers: int,
disable_mmap: bool = False,
) -> Generator[Tuple[str, torch.Tensor], None, None]:
"""Multi-threaded safetensor loader with bounded memory via a sliding window.
At most (max_workers + 1) shard files are in-flight at any time:
max_workers loading concurrently + 1 prefetched and ready to yield.
Peak CPU RAM ≈ (max_workers + 2) × shard_file_size.
"""
enable_tqdm = (
not torch.distributed.is_initialized() or torch.distributed.get_rank() == 0
)
def _load_file(st_file: str):
if disable_mmap:
with open(st_file, "rb") as f:
result = safetensors.torch.load(f.read())
else:
with safetensors.safe_open(st_file, framework="pt", device="cpu") as f:
result = {k: f.get_tensor(k) for k in f.keys()}
return result
# Sliding window: max_workers loading + 1 prefetched.
buffer_size = max_workers + 1
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
file_iter = iter(hf_weights_files)
pending: collections.deque = collections.deque()
# Seed the buffer.
for st_file in itertools.islice(file_iter, buffer_size):
pending.append(executor.submit(_load_file, st_file))
with tqdm(
total=len(hf_weights_files),
desc="Multi-thread loading shards",
disable=not enable_tqdm,
bar_format=BAR_FORMAT,
position=tqdm._get_free_pos(),
) as pbar:
while pending:
future = pending.popleft()
state_dict = future.result()
del future # let GC reclaim the Future's internal result
# Replenish: submit the next file to keep the buffer full.
next_file = next(file_iter, None)
if next_file is not None:
pending.append(executor.submit(_load_file, next_file))
for name in sorted(state_dict.keys()):
yield name, state_dict[name]
del state_dict
pbar.update(1)
def _load_pt_file(bin_file: str) -> dict: def _load_pt_file(bin_file: str) -> dict:
"""Load a PyTorch checkpoint file, handling legacy tar format. """Load a PyTorch checkpoint file, handling legacy tar format.
@@ -906,7 +927,7 @@ def pt_weights_iterator(
def multi_thread_pt_weights_iterator( def multi_thread_pt_weights_iterator(
hf_weights_files: List[str], hf_weights_files: List[str],
max_workers: int = 4, max_workers: int,
) -> Generator[Tuple[str, torch.Tensor], None, None]: ) -> Generator[Tuple[str, torch.Tensor], None, None]:
"""Multi-Thread iterate over the weights in the model bin/pt files.""" """Multi-Thread iterate over the weights in the model bin/pt files."""
enable_tqdm = ( enable_tqdm = (