diff --git a/tests/lora/test_utils.py b/tests/lora/test_utils.py index bec12eeeb48d..4a9ba66069d7 100644 --- a/tests/lora/test_utils.py +++ b/tests/lora/test_utils.py @@ -175,7 +175,7 @@ def test_get_adapter_absolute_path_local_existing(mock_abspath, mock_exist): assert get_adapter_absolute_path(path) == absolute_path -@patch("huggingface_hub.snapshot_download") +@patch("huggingface_hub.HfApi.snapshot_download") @patch("os.path.exists") def test_get_adapter_absolute_path_huggingface(mock_exist, mock_snapshot_download): # Hugging Face model identifier @@ -186,7 +186,7 @@ def test_get_adapter_absolute_path_huggingface(mock_exist, mock_snapshot_downloa assert get_adapter_absolute_path(path) == absolute_path -@patch("huggingface_hub.snapshot_download") +@patch("huggingface_hub.HfApi.snapshot_download") @patch("os.path.exists") def test_get_adapter_absolute_path_huggingface_error( mock_exist, mock_snapshot_download diff --git a/vllm/assets/video.py b/vllm/assets/video.py index 9ec2e4d16770..72cd196c68f4 100644 --- a/vllm/assets/video.py +++ b/vllm/assets/video.py @@ -7,10 +7,10 @@ import numpy as np import numpy.typing as npt -from huggingface_hub import hf_hub_download from PIL import Image from vllm.multimodal.media.audio import load_audio_pyav +from vllm.transformers_utils.repo_utils import hf_api from .base import get_cache_dir @@ -27,7 +27,7 @@ def download_video_asset(filename: str) -> str: video_path = video_directory / filename video_path_str = str(video_path) if not video_path.exists(): - video_path_str = hf_hub_download( + video_path_str = hf_api().hf_hub_download( repo_id="raushan-testing-hf/videos-test", filename=filename, repo_type="dataset", diff --git a/vllm/benchmarks/datasets/datasets.py b/vllm/benchmarks/datasets/datasets.py index 70545a3b4959..af62f049ff3a 100644 --- a/vllm/benchmarks/datasets/datasets.py +++ b/vllm/benchmarks/datasets/datasets.py @@ -31,7 +31,6 @@ import numpy as np import pybase64 as base64 -from huggingface_hub import snapshot_download from PIL import Image from typing_extensions import deprecated @@ -46,6 +45,7 @@ from vllm.multimodal.audio import get_audio_duration from vllm.multimodal.image import convert_image_mode from vllm.tokenizers import TokenizerLike +from vllm.transformers_utils.repo_utils import hf_api from vllm.utils.argparse_utils import FlexibleArgumentParser from vllm.utils.import_utils import PlaceholderModule from vllm.utils.mistral import is_mistral_tokenizer @@ -3334,7 +3334,10 @@ def __init__(self, **kwargs) -> None: self._remote_path_root = ( f"https://huggingface.co/datasets/{self.hf_name}/resolve/main" ) - self._local_path_root = snapshot_download(self.hf_name, repo_type="dataset") + self._local_path_root = hf_api().snapshot_download( + self.hf_name, + repo_type="dataset", + ) def sample( self, diff --git a/vllm/lora/utils.py b/vllm/lora/utils.py index 7b68c1f952aa..d5c9a1a6ff8a 100644 --- a/vllm/lora/utils.py +++ b/vllm/lora/utils.py @@ -4,7 +4,6 @@ import os from typing import TYPE_CHECKING -import huggingface_hub import regex as re from huggingface_hub.utils import HfHubHTTPError, HFValidationError from torch import nn @@ -37,6 +36,7 @@ from vllm.model_executor.layers.fused_moe import FusedMoE from vllm.model_executor.layers.linear import LinearBase from vllm.model_executor.utils import get_moe_expert_mapping, get_packed_modules_mapping +from vllm.transformers_utils.repo_utils import hf_api if TYPE_CHECKING: from vllm.model_executor.layers.logits_processor import LogitsProcessor @@ -340,7 +340,9 @@ def get_adapter_absolute_path(lora_path: str) -> str: error_log = "Error downloading the ModelScope model" else: # Otherwise, we assume the path is a Hugging Face Hub repo. - download_fn = lambda: huggingface_hub.snapshot_download(repo_id=lora_path) + download_fn = lambda: hf_api().snapshot_download( + repo_id=lora_path, + ) download_exceptions = (HfHubHTTPError, HFValidationError) error_log = "Error downloading the HuggingFace model" diff --git a/vllm/model_executor/model_loader/bitsandbytes_loader.py b/vllm/model_executor/model_loader/bitsandbytes_loader.py index 81526415ff2d..4d9ae267e084 100644 --- a/vllm/model_executor/model_loader/bitsandbytes_loader.py +++ b/vllm/model_executor/model_loader/bitsandbytes_loader.py @@ -10,7 +10,6 @@ import numpy as np import torch -from huggingface_hub import HfApi from packaging import version from torch import nn from transformers.utils import SAFE_WEIGHTS_INDEX_NAME @@ -48,6 +47,7 @@ set_weight_attrs, ) from vllm.platforms import current_platform +from vllm.transformers_utils.repo_utils import hf_api from vllm.utils.torch_utils import set_default_torch_dtype logger = init_logger(__name__) @@ -97,8 +97,7 @@ def _get_weight_files( if weight_files: return model_name_or_path, weight_files, pattern else: - hf_api = HfApi() - repo_files = hf_api.list_repo_files(repo_id=model_name_or_path) + repo_files = hf_api().list_repo_files(repo_id=model_name_or_path) for pattern in allowed_patterns: matching_files = fnmatch.filter(repo_files, pattern) if matching_files: diff --git a/vllm/model_executor/model_loader/gguf_loader.py b/vllm/model_executor/model_loader/gguf_loader.py index 6148caa98746..2db5efd0e5b3 100644 --- a/vllm/model_executor/model_loader/gguf_loader.py +++ b/vllm/model_executor/model_loader/gguf_loader.py @@ -8,7 +8,6 @@ import regex as re import torch import torch.nn as nn -from huggingface_hub import hf_hub_download from transformers import AutoModelForCausalLM, AutoModelForImageTextToText from vllm.config import ModelConfig, VllmConfig @@ -27,6 +26,7 @@ gguf_quant_weights_iterator_multi, ) from vllm.transformers_utils.gguf_utils import detect_gguf_multimodal +from vllm.transformers_utils.repo_utils import hf_api from vllm.utils.torch_utils import set_default_torch_dtype if TYPE_CHECKING: @@ -57,7 +57,7 @@ def _prepare_weights(self, model_config: ModelConfig): # repo id/filename.gguf if "/" in model_name_or_path and model_name_or_path.endswith(".gguf"): repo_id, filename = model_name_or_path.rsplit("/", 1) - return hf_hub_download( + return hf_api().hf_hub_download( repo_id=repo_id, filename=filename, revision=model_config.revision, diff --git a/vllm/model_executor/model_loader/tensorizer.py b/vllm/model_executor/model_loader/tensorizer.py index 37d37d55f543..736b2134604b 100644 --- a/vllm/model_executor/model_loader/tensorizer.py +++ b/vllm/model_executor/model_loader/tensorizer.py @@ -16,7 +16,6 @@ import regex as re import torch -from huggingface_hub import snapshot_download from torch import nn from torch.utils._python_dispatch import TorchDispatchMode from transformers import PretrainedConfig @@ -26,6 +25,7 @@ from vllm.logger import init_logger from vllm.model_executor.layers.vocab_parallel_embedding import VocabParallelEmbedding from vllm.platforms import current_platform +from vllm.transformers_utils.repo_utils import hf_api from vllm.utils.argparse_utils import FlexibleArgumentParser from vllm.utils.import_utils import PlaceholderModule @@ -629,7 +629,7 @@ def serialize_extra_artifacts( ) with tempfile.TemporaryDirectory() as tmpdir: - snapshot_download( + hf_api().snapshot_download( served_model_name, local_dir=tmpdir, ignore_patterns=[ diff --git a/vllm/model_executor/model_loader/weight_utils.py b/vllm/model_executor/model_loader/weight_utils.py index 972271e8c308..cbb191ebb62b 100644 --- a/vllm/model_executor/model_loader/weight_utils.py +++ b/vllm/model_executor/model_loader/weight_utils.py @@ -23,7 +23,6 @@ import numpy as np import regex as re import torch -from huggingface_hub import HfFileSystem, hf_hub_download, snapshot_download from safetensors.torch import load, load_file, safe_open, save_file from tqdm.auto import tqdm from transformers.utils import SAFE_WEIGHTS_INDEX_NAME @@ -46,6 +45,7 @@ ) from vllm.platforms import current_platform from vllm.tracing import instrument +from vllm.transformers_utils.repo_utils import hf_api, hf_fs from vllm.utils.import_utils import PlaceholderModule try: @@ -373,7 +373,7 @@ def get_quant_config( if not is_local: # Download the config files. with get_lock(model_config.model, load_config.download_dir): - hf_folder = snapshot_download( + hf_folder = hf_api().snapshot_download( model_config.model, revision=model_config.revision, allow_patterns="*.json", @@ -431,7 +431,7 @@ def get_sparse_attention_config( if not is_local: # Download the config files. with get_lock(model_name_or_path, load_config.download_dir): - hf_folder = snapshot_download( + hf_folder = hf_api().snapshot_download( model_name_or_path, revision=model_config.revision, allow_patterns="*.json", @@ -534,7 +534,7 @@ def download_weights_from_hf( # Attempt to reduce allow_patterns to a single pattern # so we only have to call snapshot_download once. try: - fs = HfFileSystem() + fs = hf_fs() file_list = fs.ls( os.path.join(model_name_or_path, subfolder or ""), detail=False, @@ -546,7 +546,7 @@ def download_weights_from_hf( # unnecessary files (e.g., from subdirectories like "original/"). index_file = f"{model_name_or_path}/{SAFE_WEIGHTS_INDEX_NAME}" if "*.safetensors" in allow_patterns and index_file in file_list: - index_path = hf_hub_download( + index_path = hf_api().hf_hub_download( repo_id=model_name_or_path, filename=SAFE_WEIGHTS_INDEX_NAME, cache_dir=cache_dir, @@ -582,7 +582,7 @@ def download_weights_from_hf( with get_lock(model_name_or_path, cache_dir): start_time = time.perf_counter() for allow_pattern in allow_patterns: - hf_folder = snapshot_download( + hf_folder = hf_api().snapshot_download( model_name_or_path, allow_patterns=allow_pattern, ignore_patterns=ignore_patterns, @@ -631,7 +631,7 @@ def download_safetensors_index_file_from_hf( with get_lock(model_name_or_path, cache_dir): try: # Download the safetensors index file. - hf_hub_download( + hf_api().hf_hub_download( repo_id=model_name_or_path, filename=index_file, cache_dir=cache_dir, diff --git a/vllm/plugins/lora_resolvers/hf_hub_resolver.py b/vllm/plugins/lora_resolvers/hf_hub_resolver.py index c152d4c29467..57ccdc2e48d8 100644 --- a/vllm/plugins/lora_resolvers/hf_hub_resolver.py +++ b/vllm/plugins/lora_resolvers/hf_hub_resolver.py @@ -3,13 +3,12 @@ import asyncio import os -from huggingface_hub import HfApi, snapshot_download - import vllm.envs as envs from vllm.logger import init_logger from vllm.lora.request import LoRARequest from vllm.lora.resolver import LoRAResolverRegistry from vllm.plugins.lora_resolvers.filesystem_resolver import FilesystemResolver +from vllm.transformers_utils.repo_utils import hf_api logger = init_logger(__name__) @@ -49,7 +48,7 @@ async def resolve_lora( return None repo_path = await asyncio.to_thread( - snapshot_download, + hf_api().snapshot_download, repo_id=maybe_repo, allow_patterns=f"{maybe_subpath}/*" if maybe_subpath != "." else "*", ) @@ -110,7 +109,10 @@ async def _get_adapter_dirs(self, repo_name: str) -> set[str]: Args: repo_name: Name of the HF hub repo to inspect. """ - repo_files = await asyncio.to_thread(HfApi().list_repo_files, repo_id=repo_name) + repo_files = await asyncio.to_thread( + hf_api().list_repo_files, + repo_id=repo_name, + ) adapter_dirs = { os.path.dirname(name) for name in repo_files diff --git a/vllm/tokenizers/grok2.py b/vllm/tokenizers/grok2.py index 61fa1107e2a3..612af5374082 100644 --- a/vllm/tokenizers/grok2.py +++ b/vllm/tokenizers/grok2.py @@ -8,7 +8,6 @@ from pathlib import Path from typing import Any, Literal, overload -from huggingface_hub import hf_hub_download from huggingface_hub.utils import ( EntryNotFoundError, HfHubHTTPError, @@ -20,6 +19,7 @@ from vllm.entrypoints.chat_utils import ChatCompletionMessageParam from vllm.logger import init_logger +from vllm.transformers_utils.repo_utils import hf_api from .protocol import TokenizerLike @@ -70,7 +70,7 @@ def _maybe_load_tokenizer_config( return {} try: - config_file = hf_hub_download( + config_file = hf_api().hf_hub_download( repo_id=repo_id, filename="tokenizer_config.json", revision=revision, @@ -208,7 +208,7 @@ def from_pretrained( repo_id = None else: vocab_file = Path( - hf_hub_download( + hf_api().hf_hub_download( repo_id=str(path_or_repo_id), filename="tokenizer.tok.json", revision=revision, diff --git a/vllm/tokenizers/kimi_audio.py b/vllm/tokenizers/kimi_audio.py index d2b0a2a557ef..10f57a7f7ded 100644 --- a/vllm/tokenizers/kimi_audio.py +++ b/vllm/tokenizers/kimi_audio.py @@ -10,13 +10,13 @@ import pybase64 import tiktoken -from huggingface_hub import hf_hub_download from transformers import AddedToken, BatchEncoding from transformers.utils import chat_template_utils as hf_chat_utils from vllm.entrypoints.chat_utils import ChatCompletionMessageParam from vllm.logger import init_logger from vllm.tokenizers.protocol import TokenizerLike +from vllm.transformers_utils.repo_utils import hf_api logger = init_logger(__name__) @@ -78,7 +78,7 @@ def from_pretrained( # Try to download tiktoken.model or tokenizer.model try: - vocab_path = hf_hub_download( + vocab_path = hf_api().hf_hub_download( repo_id=repo_id, filename="tiktoken.model", revision=revision, @@ -87,7 +87,7 @@ def from_pretrained( vocab_file = Path(vocab_path) except Exception: try: - vocab_path = hf_hub_download( + vocab_path = hf_api().hf_hub_download( repo_id=repo_id, filename="tokenizer.model", revision=revision, @@ -101,7 +101,7 @@ def from_pretrained( # Also download tokenizer_config.json if available with contextlib.suppress(Exception): - hf_hub_download( + hf_api().hf_hub_download( repo_id=repo_id, filename="tokenizer_config.json", revision=revision, diff --git a/vllm/transformers_utils/config.py b/vllm/transformers_utils/config.py index ffe5941bcc08..f940739a96c3 100644 --- a/vllm/transformers_utils/config.py +++ b/vllm/transformers_utils/config.py @@ -12,7 +12,7 @@ import huggingface_hub import torch -from huggingface_hub import constants, get_safetensors_metadata +from huggingface_hub import constants from packaging.version import Version from safetensors.torch import _TYPES as _SAFETENSORS_TO_TORCH_DTYPE from transformers import GenerationConfig, PretrainedConfig @@ -43,6 +43,7 @@ from .repo_utils import ( file_or_path_exists, get_hf_file_to_dict, + hf_api, list_repo_files, try_get_local_file, with_retry, @@ -1143,7 +1144,7 @@ def try_get_safetensors_metadata( revision: str | None = None, ): get_safetensors_metadata_partial = partial( - get_safetensors_metadata, model, revision=revision + hf_api().get_safetensors_metadata, model, revision=revision ) try: @@ -1237,7 +1238,7 @@ def get_safetensors_params_metadata( # local HF cache: weights may already be cached from a prior run, and # weight loading itself uses the same cache. try: - local_dir = huggingface_hub.snapshot_download( + local_dir = hf_api().snapshot_download( repo_id=model, revision=revision, allow_patterns=["*.safetensors"], diff --git a/vllm/transformers_utils/repo_utils.py b/vllm/transformers_utils/repo_utils.py index 704d505617f2..8385057e9111 100644 --- a/vllm/transformers_utils/repo_utils.py +++ b/vllm/transformers_utils/repo_utils.py @@ -12,8 +12,7 @@ from typing import TypeVar import huggingface_hub -from huggingface_hub import hf_hub_download, try_to_load_from_cache -from huggingface_hub import list_repo_files as hf_list_repo_files +from huggingface_hub import HfApi, try_to_load_from_cache from huggingface_hub.utils import ( EntryNotFoundError, HfHubHTTPError, @@ -24,9 +23,31 @@ from vllm import envs from vllm.logger import init_logger +from vllm.version import __version__ as VLLM_VERSION logger = init_logger(__name__) +_hf_api: HfApi | None = None + + +def hf_api() -> HfApi: + """Return a shared HfApi instance tagged with vLLM's library info.""" + global _hf_api + if _hf_api is None: + _hf_api = HfApi( + library_name="vllm", + library_version=VLLM_VERSION, + ) + return _hf_api + + +def hf_fs() -> "huggingface_hub.HfFileSystem": + """Return a fresh HfFileSystem tagged with vLLM's library info.""" + return huggingface_hub.HfFileSystem( + library_name="vllm", + library_version=VLLM_VERSION, + ) + _R = TypeVar("_R") @@ -80,7 +101,7 @@ def lookup_files() -> list[str]: revision=revision, token=os.getenv("MODELSCOPE_API_TOKEN", None), ) - return hf_list_repo_files( + return hf_api().list_repo_files( repo_id, revision=revision, repo_type=repo_type, token=token ) except huggingface_hub.errors.OfflineModeIsEnabled: @@ -215,9 +236,10 @@ def get_model_path(model: str | Path, revision: str | None = None): return snapshot_download(model_id=model, **common_kwargs) - from huggingface_hub import snapshot_download - - return snapshot_download(repo_id=model, **common_kwargs) + return hf_api().snapshot_download( + repo_id=model, + **common_kwargs, + ) def _try_download_from_hf_hub( @@ -231,7 +253,13 @@ def _try_download_from_hf_hub( if Path(model).is_dir(): return None try: - return Path(hf_hub_download(model, file_name, revision=revision)) + return Path( + hf_api().hf_hub_download( + model, + file_name, + revision=revision, + ) + ) except huggingface_hub.errors.OfflineModeIsEnabled: return None except (