@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / cd77382ac1
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 15, 14:45 UTC

Improve configs - `LoadConfig` (#16422)

Signed-off-by: Harry Mellor <19981378+hmellor@users.noreply.github.com>

Harry Mellor committed Apr 11, 2025 at 21:27 UTC cd77382ac176b3acc717d79be7981dc60e71dbe3
3 files changed +96 -97
vllm/config.py
+42 -35
@@ -17,7 +17,7 @@ from dataclasses import (MISSING, dataclass, field, fields, is_dataclass,
17 from importlib.util import find_spec
18 from pathlib import Path
19 from typing import (TYPE_CHECKING, Any, Callable, ClassVar, Final, Literal,
20 - Optional, Protocol, Union)
20 + Optional, Protocol, TypeVar, Union)
21
22 import torch
23 from pydantic import BaseModel, Field, PrivateAttr
@@ -45,6 +45,7 @@ from vllm.utils import (GiB_bytes, LayerBlockType, cuda_device_count_stateless,
45 random_uuid, resolve_obj_by_qualname)
46
47 if TYPE_CHECKING:
48 + from _typeshed import DataclassInstance
49 from ray.util.placement_group import PlacementGroup
50
51 from vllm.executor.executor_base import ExecutorBase
@@ -53,8 +54,11 @@ if TYPE_CHECKING:
54 from vllm.model_executor.model_loader.loader import BaseModelLoader
55 from vllm.transformers_utils.tokenizer_group.base_tokenizer_group import (
56 BaseTokenizerGroup)
57 +
58 + Config = TypeVar("Config", bound=DataclassInstance)
59 else:
60 QuantizationConfig = None
61 + Config = TypeVar("Config")
62
63 logger = init_logger(__name__)
64
@@ -159,7 +163,7 @@ def get_attr_docs(cls: type[Any]) -> dict[str, str]:
163 return out
164
165
162 -def config(cls: type[Any]) -> type[Any]:
166 +def config(cls: type[Config]) -> type[Config]:
167 """
168 A decorator that ensures all fields in a dataclass have default values
169 and that each field has a docstring.
@@ -1431,44 +1435,47 @@ class LoadFormat(str, enum.Enum):
1435 FASTSAFETENSORS = "fastsafetensors"
1436
1437
1438 +@config
1439 @dataclass
1440 class LoadConfig:
1436 - """
1437 - download_dir: Directory to download and load the weights, default to the
1438 - default cache directory of huggingface.
1439 - load_format: The format of the model weights to load:
1440 - "auto" will try to load the weights in the safetensors format and
1441 - fall back to the pytorch bin format if safetensors format is
1442 - not available.
1443 - "pt" will load the weights in the pytorch bin format.
1444 - "safetensors" will load the weights in the safetensors format.
1445 - "npcache" will load the weights in pytorch format and store
1446 - a numpy cache to speed up the loading.
1447 - "dummy" will initialize the weights with random values, which is
1448 - mainly for profiling.
1449 - "tensorizer" will use CoreWeave's tensorizer library for
1450 - fast weight loading.
1451 - "bitsandbytes" will load nf4 type weights.
1452 - "sharded_state" will load weights from pre-sharded checkpoint files,
1453 - supporting efficient loading of tensor-parallel models.
1454 - "gguf" will load weights from GGUF format files.
1455 - "mistral" will load weights from consolidated safetensors files used
1456 - by Mistral models.
1457 - "runai_streamer" will load weights from RunAI streamer format files.
1458 - model_loader_extra_config: The extra config for the model loader.
1459 - ignore_patterns: The list of patterns to ignore when loading the model.
1460 - Default to "original/**/*" to avoid repeated loading of llama's
1461 - checkpoints.
1462 - use_tqdm_on_load: Whether to enable tqdm for showing progress bar during
1463 - loading. Default to True
1464 - """
1465 -
1466 - load_format: Union[str, LoadFormat, "BaseModelLoader"] = LoadFormat.AUTO
1441 + """Configuration for loading the model weights."""
1442 +
1443 + load_format: Union[str, LoadFormat,
1444 + "BaseModelLoader"] = LoadFormat.AUTO.value
1445 + """The format of the model weights to load:\n
1446 + - "auto" will try to load the weights in the safetensors format and fall
1447 + back to the pytorch bin format if safetensors format is not available.\n
1448 + - "pt" will load the weights in the pytorch bin format.\n
1449 + - "safetensors" will load the weights in the safetensors format.\n
1450 + - "npcache" will load the weights in pytorch format and store a numpy cache
1451 + to speed up the loading.\n
1452 + - "dummy" will initialize the weights with random values, which is mainly
1453 + for profiling.\n
1454 + - "tensorizer" will use CoreWeave's tensorizer library for fast weight
1455 + loading. See the Tensorize vLLM Model script in the Examples section for
1456 + more information.\n
1457 + - "runai_streamer" will load the Safetensors weights using Run:ai Model
1458 + Streamer.\n
1459 + - "bitsandbytes" will load the weights using bitsandbytes quantization.\n
1460 + - "sharded_state" will load weights from pre-sharded checkpoint files,
1461 + supporting efficient loading of tensor-parallel models.\n
1462 + - "gguf" will load weights from GGUF format files (details specified in
1463 + https://github.com/ggml-org/ggml/blob/master/docs/gguf.md).\n
1464 + - "mistral" will load weights from consolidated safetensors files used by
1465 + Mistral models."""
1466 download_dir: Optional[str] = None
1468 - model_loader_extra_config: Optional[Union[str, dict]] = field(
1469 - default_factory=dict)
1467 + """Directory to download and load the weights, default to the default
1468 + cache directory of Hugging Face."""
1469 + model_loader_extra_config: Optional[Union[str, dict]] = None
1470 + """Extra config for model loader. This will be passed to the model loader
1471 + corresponding to the chosen load_format. This should be a JSON string that
1472 + will be parsed into a dictionary."""
1473 ignore_patterns: Optional[Union[list[str], str]] = None
1474 + """The list of patterns to ignore when loading the model. Default to
1475 + "original/**/*" to avoid repeated loading of llama's checkpoints."""
1476 use_tqdm_on_load: bool = True
1477 + """Whether to enable tqdm for showing progress bar when loading model
1478 + weights."""
1479
1480 def compute_hash(self) -> str:
1481 """
vllm/engine/arg_utils.py
+33 -55
@@ -101,8 +101,8 @@ class EngineArgs:
101 tokenizer_mode: str = 'auto'
102 trust_remote_code: bool = False
103 allowed_local_media_path: str = ""
104 - download_dir: Optional[str] = None
105 - load_format: str = 'auto'
104 + download_dir: Optional[str] = LoadConfig.download_dir
105 + load_format: str = LoadConfig.load_format
106 config_format: ConfigFormat = ConfigFormat.AUTO
107 dtype: str = 'auto'
108 kv_cache_dtype: str = 'auto'
@@ -174,8 +174,10 @@ class EngineArgs:
174 ray_workers_use_nsight: bool = ParallelConfig.ray_workers_use_nsight
175 num_gpu_blocks_override: Optional[int] = None
176 num_lookahead_slots: int = 0
177 - model_loader_extra_config: Optional[dict] = None
178 - ignore_patterns: Optional[Union[str, List[str]]] = None
177 + model_loader_extra_config: Optional[
178 + dict] = LoadConfig.model_loader_extra_config
179 + ignore_patterns: Optional[Union[str,
180 + List[str]]] = LoadConfig.ignore_patterns
181 preemption_mode: Optional[str] = None
182
183 scheduler_delay_factor: float = 0.0
@@ -213,7 +215,7 @@ class EngineArgs:
215 additional_config: Optional[Dict[str, Any]] = None
216 enable_reasoning: Optional[bool] = None
217 reasoning_parser: Optional[str] = None
216 - use_tqdm_on_load: bool = True
218 + use_tqdm_on_load: bool = LoadConfig.use_tqdm_on_load
219
220 def __post_init__(self):
221 if not self.tokenizer:
@@ -234,9 +236,13 @@ class EngineArgs:
236 def add_cli_args(parser: FlexibleArgumentParser) -> FlexibleArgumentParser:
237 """Shared CLI arguments for vLLM engine."""
238
239 + def is_type_in_union(cls: type[Any], type: type[Any]) -> bool:
240 + """Check if the class is a type in a union type."""
241 + return get_origin(cls) is Union and type in get_args(cls)
242 +
243 def is_optional(cls: type[Any]) -> bool:
244 """Check if the class is an optional type."""
239 - return get_origin(cls) is Union and type(None) in get_args(cls)
245 + return is_type_in_union(cls, type(None))
246
247 def get_kwargs(cls: type[Any]) -> Dict[str, Any]:
248 cls_docs = get_attr_docs(cls)
@@ -255,6 +261,10 @@ class EngineArgs:
261 if is_optional(field.type):
262 kwargs[name]["type"] = nullable_str
263 continue
264 + # Handle str in union fields
265 + if is_type_in_union(field.type, str):
266 + kwargs[name]["type"] = str
267 + continue
268 kwargs[name]["type"] = field.type
269 return kwargs
270
@@ -333,38 +343,23 @@ class EngineArgs:
343 "from directories specified by the server file system. "
344 "This is a security risk. "
345 "Should only be enabled in trusted environments.")
336 - parser.add_argument('--download-dir',
337 - type=nullable_str,
338 - default=EngineArgs.download_dir,
339 - help='Directory to download and load the weights.')
340 - parser.add_argument(
341 - '--load-format',
342 - type=str,
343 - default=EngineArgs.load_format,
344 - choices=[f.value for f in LoadFormat],
345 - help='The format of the model weights to load.\n\n'
346 - '* "auto" will try to load the weights in the safetensors format '
347 - 'and fall back to the pytorch bin format if safetensors format '
348 - 'is not available.\n'
349 - '* "pt" will load the weights in the pytorch bin format.\n'
350 - '* "safetensors" will load the weights in the safetensors format.\n'
351 - '* "npcache" will load the weights in pytorch format and store '
352 - 'a numpy cache to speed up the loading.\n'
353 - '* "dummy" will initialize the weights with random values, '
354 - 'which is mainly for profiling.\n'
355 - '* "tensorizer" will load the weights using tensorizer from '
356 - 'CoreWeave. See the Tensorize vLLM Model script in the Examples '
357 - 'section for more information.\n'
358 - '* "runai_streamer" will load the Safetensors weights using Run:ai'
359 - 'Model Streamer.\n'
360 - '* "bitsandbytes" will load the weights using bitsandbytes '
361 - 'quantization.\n'
362 - '* "sharded_state" will load weights from pre-sharded checkpoint '
363 - 'files, supporting efficient loading of tensor-parallel models\n'
364 - '* "gguf" will load weights from GGUF format files (details '
365 - 'specified in https://github.com/ggml-org/ggml/blob/master/docs/gguf.md).\n'
366 - '* "mistral" will load weights from consolidated safetensors files '
367 - 'used by Mistral models.\n')
346 + # Model loading arguments
347 + load_kwargs = get_kwargs(LoadConfig)
348 + load_group = parser.add_argument_group(
349 + title="LoadConfig",
350 + description=LoadConfig.__doc__,
351 + )
352 + load_group.add_argument('--load-format',
353 + choices=[f.value for f in LoadFormat],
354 + **load_kwargs["load_format"])
355 + load_group.add_argument('--download-dir',
356 + **load_kwargs["download_dir"])
357 + load_group.add_argument('--model-loader-extra-config',
358 + **load_kwargs["model_loader_extra_config"])
359 + load_group.add_argument('--use-tqdm-on-load',
360 + action=argparse.BooleanOptionalAction,
361 + **load_kwargs["use_tqdm_on_load"])
362 +
363 parser.add_argument(
364 '--config-format',
365 default=EngineArgs.config_format,
@@ -770,14 +765,6 @@ class EngineArgs:
765 default=1,
766 help=('Maximum number of forward steps per '
767 'scheduler call.'))
773 - parser.add_argument(
774 - '--use-tqdm-on-load',
775 - dest='use_tqdm_on_load',
776 - action=argparse.BooleanOptionalAction,
777 - default=EngineArgs.use_tqdm_on_load,
778 - help='Whether to enable/disable progress bar '
779 - 'when loading model weights.',
780 - )
768
769 parser.add_argument(
770 '--multi-step-stream-outputs',
@@ -806,15 +793,6 @@ class EngineArgs:
793 default=None,
794 help='The configurations for speculative decoding.'
795 ' Should be a JSON string.')
809 -
810 - parser.add_argument('--model-loader-extra-config',
811 - type=nullable_str,
812 - default=EngineArgs.model_loader_extra_config,
813 - help='Extra config for model loader. '
814 - 'This will be passed to the model loader '
815 - 'corresponding to the chosen load_format. '
816 - 'This should be a JSON string that will be '
817 - 'parsed into a dictionary.')
796 parser.add_argument(
797 '--ignore-patterns',
798 action="append",
vllm/utils.py
+21 -7
@@ -2,7 +2,6 @@
2
3 from __future__ import annotations
4
5 -import argparse
5 import asyncio
6 import concurrent
7 import contextlib
@@ -25,6 +24,7 @@ import socket
24 import subprocess
25 import sys
26 import tempfile
27 +import textwrap
28 import threading
29 import time
30 import traceback
@@ -32,6 +32,8 @@ import types
32 import uuid
33 import warnings
34 import weakref
35 +from argparse import (Action, ArgumentDefaultsHelpFormatter, ArgumentParser,
36 + ArgumentTypeError)
37 from asyncio import FIRST_COMPLETED, AbstractEventLoop, Task
38 from collections import UserDict, defaultdict
39 from collections.abc import (AsyncGenerator, Awaitable, Generator, Hashable,
@@ -1209,7 +1211,7 @@ def run_once(f: Callable[P, None]) -> Callable[P, None]:
1211 return wrapper
1212
1213
1212 -class StoreBoolean(argparse.Action):
1214 +class StoreBoolean(Action):
1215
1216 def __call__(self, parser, namespace, values, option_string=None):
1217 if values.lower() == "true":
@@ -1221,15 +1223,28 @@ class StoreBoolean(argparse.Action):
1223 "Expected 'true' or 'false'.")
1224
1225
1224 -class SortedHelpFormatter(argparse.ArgumentDefaultsHelpFormatter):
1226 +class SortedHelpFormatter(ArgumentDefaultsHelpFormatter):
1227 """SortedHelpFormatter that sorts arguments by their option strings."""
1228
1229 + def _split_lines(self, text, width):
1230 + """
1231 + 1. Sentences split across lines have their single newlines removed.
1232 + 2. Paragraphs and explicit newlines are split into separate lines.
1233 + 3. Each line is wrapped to the specified width (width of terminal).
1234 + """
1235 + # The patterns also include whitespace after the newline
1236 + single_newline = re.compile("(?<!\n)\n(?!\n)\s*")
1237 + multiple_newlines = re.compile("\n{2,}\s*")
1238 + text = single_newline.sub(' ', text)
1239 + lines = re.split(multiple_newlines, text)
1240 + return sum([textwrap.wrap(line, width) for line in lines], [])
1241 +
1242 def add_arguments(self, actions):
1243 actions = sorted(actions, key=lambda x: x.option_strings)
1244 super().add_arguments(actions)
1245
1246
1232 -class FlexibleArgumentParser(argparse.ArgumentParser):
1247 +class FlexibleArgumentParser(ArgumentParser):
1248 """ArgumentParser that allows both underscore and dash in names."""
1249
1250 def __init__(self, *args, **kwargs):
@@ -1280,11 +1295,10 @@ class FlexibleArgumentParser(argparse.ArgumentParser):
1295 value = int(value)
1296 except ValueError:
1297 msg = "Port must be an integer"
1283 - raise argparse.ArgumentTypeError(msg) from None
1298 + raise ArgumentTypeError(msg) from None
1299
1300 if not (1024 <= value <= 65535):
1286 - raise argparse.ArgumentTypeError(
1287 - "Port must be between 1024 and 65535")
1301 + raise ArgumentTypeError("Port must be between 1024 and 65535")
1302
1303 return value
1304