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, 18:30 UTC
[Core] Update dtype detection and defaults (#14858)
Signed-off-by: DarkLight1337 <tlleungac@connect.ust.hk>
Cyrus Leung committed
Mar 19, 2025 at 13:49 UTC
f690372b6803c43870aefa631ab207ea3d163b1d
22 files changed
+175
-227
tests/compile/test_basic_correctness.py
+1
-1
@@ -60,7 +60,7 @@ class TestSetting:
60
# embedding model
61
TestSetting(
62
model="BAAI/bge-multilingual-gemma2",
63
- model_args=["--task", "embed"],
63
+ model_args=["--task", "embed", "--dtype", "bfloat16"],
64
pp_size=1,
65
tp_size=1,
66
attn_backend="FLASH_ATTN",
tests/conftest.py
+63
-53
@@ -14,8 +14,8 @@ import torch.nn as nn
14
import torch.nn.functional as F
15
from huggingface_hub import snapshot_download
16
from PIL import Image
17
-from transformers import (AutoModelForCausalLM, AutoTokenizer, BatchEncoding,
18
- BatchFeature)
17
+from transformers import (AutoConfig, AutoModelForCausalLM, AutoTokenizer,
18
+ BatchEncoding, BatchFeature)
19
from transformers.models.auto.auto_factory import _BaseAutoModelClass
20
21
from tests.models.utils import (TokensTextLogprobs,
@@ -23,7 +23,7 @@ from tests.models.utils import (TokensTextLogprobs,
23
from vllm import LLM, SamplingParams
24
from vllm.assets.image import ImageAsset
25
from vllm.assets.video import VideoAsset
26
-from vllm.config import TaskOption, TokenizerPoolConfig
26
+from vllm.config import TaskOption, TokenizerPoolConfig, _get_and_verify_dtype
27
from vllm.connections import global_http_connection
28
from vllm.distributed import (cleanup_dist_env_and_memory,
29
init_distributed_environment,
@@ -34,8 +34,7 @@ from vllm.inputs import (ExplicitEncoderDecoderPrompt, TextPrompt,
34
from vllm.logger import init_logger
35
from vllm.outputs import RequestOutput
36
from vllm.sampling_params import BeamSearchParams
37
-from vllm.utils import (STR_DTYPE_TO_TORCH_DTYPE, cuda_device_count_stateless,
38
- identity, is_list_of)
37
+from vllm.utils import cuda_device_count_stateless, is_list_of
38
39
logger = init_logger(__name__)
40
@@ -271,14 +270,18 @@ _R = TypeVar("_R")
270
271
class HfRunner:
272
274
- def wrap_device(self, x: _T, device: Optional[str] = None) -> _T:
273
+ def get_default_device(self):
274
from vllm.platforms import current_platform
275
+
276
+ return ("cpu" if current_platform.is_cpu()
277
+ or current_platform.is_openvino() else "cuda")
278
+
279
+ def wrap_device(self, x: _T, device: Optional[str] = None) -> _T:
280
if x is None or isinstance(x, (bool, )):
281
return x
282
283
if device is None:
280
- device = "cpu" if current_platform.is_cpu(
281
- ) or current_platform.is_openvino() else "cuda"
284
+ device = self.device
285
286
if isinstance(x, dict):
287
return {k: self.wrap_device(v, device) for k, v in x.items()}
@@ -291,45 +294,59 @@ class HfRunner:
294
def __init__(
295
self,
296
model_name: str,
294
- dtype: str = "half",
297
+ dtype: str = "auto",
298
*,
299
model_kwargs: Optional[dict[str, Any]] = None,
300
is_sentence_transformer: bool = False,
301
is_cross_encoder: bool = False,
302
skip_tokenizer_init: bool = False,
303
auto_cls: type[_BaseAutoModelClass] = AutoModelForCausalLM,
301
- postprocess_inputs: Callable[..., BatchEncoding] = identity,
304
) -> None:
303
- torch_dtype = STR_DTYPE_TO_TORCH_DTYPE[dtype]
304
-
305
self.model_name = model_name
306
307
+ self.config = AutoConfig.from_pretrained(
308
+ model_name,
309
+ trust_remote_code=True,
310
+ )
311
+ self.device = self.get_default_device()
312
+ self.dtype = torch_dtype = _get_and_verify_dtype(self.config, dtype)
313
+
314
+ model_kwargs = model_kwargs if model_kwargs is not None else {}
315
+ model_kwargs.setdefault("torch_dtype", torch_dtype)
316
+
317
if is_sentence_transformer:
318
# Lazy init required for AMD CI
319
from sentence_transformers import SentenceTransformer
310
- self.model = self.wrap_device(
311
- SentenceTransformer(
312
- model_name,
313
- device="cpu",
314
- trust_remote_code=True,
315
- ).to(dtype=torch_dtype))
320
+
321
+ self.model = SentenceTransformer(
322
+ model_name,
323
+ device=self.device,
324
+ model_kwargs=model_kwargs,
325
+ trust_remote_code=True,
326
+ )
327
elif is_cross_encoder:
328
# Lazy init required for AMD CI
329
from sentence_transformers import CrossEncoder
319
- self.model = CrossEncoder(model_name,
320
- device="cpu",
321
- trust_remote_code=True)
322
- self.model.model = self.wrap_device(self.model.model)\
323
- .to(dtype=torch_dtype)
330
+
331
+ self.model = CrossEncoder(
332
+ model_name,
333
+ device=self.device,
334
+ automodel_args=model_kwargs,
335
+ trust_remote_code=True,
336
+ )
337
else:
325
- model_kwargs = model_kwargs if model_kwargs is not None else {}
326
- self.model = self.wrap_device(
327
- auto_cls.from_pretrained(
328
- model_name,
329
- torch_dtype=torch_dtype,
330
- trust_remote_code=True,
331
- **model_kwargs,
332
- ))
338
+ model = auto_cls.from_pretrained(
339
+ model_name,
340
+ trust_remote_code=True,
341
+ **model_kwargs,
342
+ )
343
+
344
+ if (getattr(model, "quantization_method", None) != "bitsandbytes"
345
+ and len({p.device
346
+ for p in model.parameters()}) < 2):
347
+ model = model.to(self.device)
348
+
349
+ self.model = model
350
351
if not skip_tokenizer_init:
352
self.tokenizer = AutoTokenizer.from_pretrained(
@@ -349,16 +366,13 @@ class HfRunner:
366
if skip_tokenizer_init:
367
self.tokenizer = self.processor.tokenizer
368
352
- self.dtype = dtype
353
- self.postprocess_inputs = postprocess_inputs
354
-
369
def get_inputs(
370
self,
371
prompts: list[str],
372
images: Optional[PromptImageInput] = None,
373
videos: Optional[PromptVideoInput] = None,
374
audios: Optional[PromptAudioInput] = None,
361
- ) -> list[BatchEncoding]:
375
+ ) -> list[Union[BatchFeature, BatchEncoding]]:
376
if images is not None:
377
assert len(prompts) == len(images)
378
@@ -368,7 +382,7 @@ class HfRunner:
382
if audios is not None:
383
assert len(prompts) == len(audios)
384
371
- all_inputs: list[BatchEncoding] = []
385
+ all_inputs: list[Union[BatchFeature, BatchEncoding]] = []
386
for i, prompt in enumerate(prompts):
387
processor_kwargs: dict[str, Any] = {
388
"text": prompt,
@@ -384,7 +398,8 @@ class HfRunner:
398
processor_kwargs["sampling_rate"] = sr
399
400
inputs = self.processor(**processor_kwargs)
387
- inputs = self.postprocess_inputs(inputs, dtype=self.dtype)
401
+ if isinstance(inputs, BatchFeature):
402
+ inputs = inputs.to(dtype=self.dtype)
403
404
all_inputs.append(inputs)
405
@@ -417,7 +432,7 @@ class HfRunner:
432
outputs: list[tuple[list[list[int]], list[str]]] = []
433
for inputs in all_inputs:
434
output_ids = self.model.generate(
420
- **self.wrap_device(inputs, device=self.model.device.type),
435
+ **self.wrap_device(inputs),
436
use_cache=True,
437
**kwargs,
438
)
@@ -488,7 +503,7 @@ class HfRunner:
503
all_logprobs: list[list[torch.Tensor]] = []
504
for inputs in all_inputs:
505
output = self.model.generate(
491
- **self.wrap_device(inputs, device=self.model.device.type),
506
+ **self.wrap_device(inputs),
507
use_cache=True,
508
do_sample=False,
509
max_new_tokens=max_tokens,
@@ -569,7 +584,7 @@ class HfRunner:
584
585
for inputs in all_inputs:
586
output = self.model.generate(
572
- **self.wrap_device(inputs, device=self.model.device.type),
587
+ **self.wrap_device(inputs),
588
use_cache=True,
589
do_sample=False,
590
max_new_tokens=max_tokens,
@@ -620,19 +635,15 @@ class HfRunner:
635
if images is not None and images[i] is not None:
636
processor_kwargs["images"] = images[i]
637
623
- encoder_inputs = self.wrap_device(
624
- self.processor(**processor_kwargs),
625
- device=self.model.device.type,
626
- )
638
+ encoder_inputs = self.processor(**processor_kwargs)
639
+ encoder_inputs = self.wrap_device(encoder_inputs)
640
641
if decoder_prompt is None:
642
decoder_input_ids = None
643
else:
631
- decoder_input_ids = self.wrap_device(
632
- self.tokenizer(decoder_prompt,
633
- return_tensors="pt").input_ids,
634
- device=self.model.device.type,
635
- )
644
+ decoder_inputs = self.tokenizer(decoder_prompt,
645
+ return_tensors="pt")
646
+ decoder_input_ids = self.wrap_device(decoder_inputs.input_ids)
647
648
output = self.model.generate(
649
decoder_input_ids=decoder_input_ids,
@@ -684,6 +695,7 @@ class VllmRunner:
695
"""
696
The default value of some arguments have been modified from
697
:class:`~vllm.LLM` as follows:
698
+
699
- `trust_remote_code`: Set to `True` instead of `False` for convenience.
700
- `seed`: Set to `0` instead of `None` for test reproducibility.
701
- `max_model_len`: Set to `1024` instead of `None` to reduce memory usage.
@@ -701,10 +713,8 @@ class VllmRunner:
713
tokenizer_mode: str = "auto",
714
trust_remote_code: bool = True,
715
seed: Optional[int] = 0,
704
- # Use smaller max model length, otherwise bigger model cannot run due
705
- # to kv cache size limit.
716
max_model_len: int = 1024,
707
- dtype: str = "half",
717
+ dtype: str = "auto",
718
disable_log_stats: bool = True,
719
tensor_parallel_size: int = 1,
720
block_size: int = 16,
@@ -1110,4 +1120,4 @@ def pytest_collection_modifyitems(config, items):
1120
skip_optional = pytest.mark.skip(reason="need --optional option to run")
1121
for item in items:
1122
if "optional" in item.keywords:
1113
- item.add_marker(skip_optional)
\ No newline at end of file
1123
+ item.add_marker(skip_optional)
tests/entrypoints/llm/test_chat.py
-1
@@ -64,7 +64,6 @@ def test_multi_chat():
64
def test_chat_multi_image(image_urls: list[str]):
65
llm = LLM(
66
model="microsoft/Phi-3.5-vision-instruct",
67
- dtype="bfloat16",
67
max_model_len=4096,
68
max_num_seqs=5,
69
enforce_eager=True,
tests/entrypoints/openai/test_audio.py
-2
@@ -18,8 +18,6 @@ TEST_AUDIO_URLS = [
18
@pytest.fixture(scope="module")
19
def server():
20
args = [
21
- "--dtype",
22
- "bfloat16",
21
"--max-model-len",
22
"2048",
23
"--max-num-seqs",
tests/entrypoints/openai/test_video.py
-2
@@ -24,8 +24,6 @@ def server():
24
args = [
25
"--task",
26
"generate",
27
- "--dtype",
28
- "bfloat16",
27
"--max-model-len",
28
"32768",
29
"--max-num-seqs",
tests/entrypoints/openai/test_vision.py
-2
@@ -25,8 +25,6 @@ def server():
25
args = [
26
"--task",
27
"generate",
28
- "--dtype",
29
- "bfloat16",
28
"--max-model-len",
29
"2048",
30
"--max-num-seqs",
tests/entrypoints/openai/test_vision_embedding.py
-2
@@ -28,8 +28,6 @@ def server():
28
args = [
29
"--task",
30
"embed",
31
- "--dtype",
32
- "bfloat16",
31
"--max-model-len",
32
"2048",
33
"--max-num-seqs",
tests/entrypoints/test_chat_utils.py
+3
-3
@@ -34,7 +34,7 @@ def phi3v_model_config():
34
tokenizer=PHI3V_MODEL_ID,
35
tokenizer_mode="auto",
36
trust_remote_code=True,
37
- dtype="bfloat16",
37
+ dtype="auto",
38
seed=0,
39
limit_mm_per_prompt={
40
"image": 2,
@@ -58,7 +58,7 @@ def mllama_model_config():
58
tokenizer=MLLAMA_MODEL_ID,
59
tokenizer_mode="auto",
60
trust_remote_code=True,
61
- dtype="bfloat16",
61
+ dtype="auto",
62
seed=0,
63
limit_mm_per_prompt={
64
"image": 2,
@@ -669,7 +669,7 @@ def test_multimodal_image_parsing_matches_hf(model, image_url):
669
tokenizer=MLLAMA_MODEL_ID,
670
tokenizer_mode="auto",
671
trust_remote_code=True,
672
- dtype="bfloat16",
672
+ dtype="auto",
673
seed=0,
674
limit_mm_per_prompt={
675
"image": 2,
tests/models/decoder_only/audio_language/test_ultravox.py
+2
-13
@@ -5,11 +5,10 @@ from typing import Optional
5
import numpy as np
6
import pytest
7
import pytest_asyncio
8
-from transformers import AutoModel, AutoTokenizer, BatchEncoding
8
+from transformers import AutoModel, AutoTokenizer
9
10
from vllm.multimodal.audio import resample_audio
11
from vllm.sequence import SampleLogprobs
12
-from vllm.utils import STR_DTYPE_TO_TORCH_DTYPE
12
13
from ....conftest import HfRunner, VllmRunner
14
from ....utils import RemoteOpenAIServer
@@ -107,8 +106,6 @@ def run_test(
106
**kwargs,
107
):
108
"""Inference result should be the same between hf and vllm."""
110
- torch_dtype = STR_DTYPE_TO_TORCH_DTYPE[dtype]
111
-
109
# NOTE: take care of the order. run vLLM first, and then run HF.
110
# vLLM needs a fresh new process without cuda initialization.
111
# if we run HF first, the cuda initialization will be done and it
@@ -124,15 +121,7 @@ def run_test(
121
for vllm_prompt, _, audio in prompts_and_audios
122
]
123
127
- def process(hf_inputs: BatchEncoding, **kwargs):
128
- hf_inputs["audio_values"] = hf_inputs["audio_values"] \
129
- .to(torch_dtype) # type: ignore
130
- return hf_inputs
131
-
132
- with hf_runner(model,
133
- dtype=dtype,
134
- postprocess_inputs=process,
135
- auto_cls=AutoModel) as hf_model:
124
+ with hf_runner(model, dtype=dtype, auto_cls=AutoModel) as hf_model:
125
hf_outputs_per_audio = [
126
hf_model.generate_greedy_logprobs_limit(
127
[hf_prompt],
tests/models/decoder_only/vision_language/test_models.py
+3
-36
@@ -122,9 +122,6 @@ VLM_TEST_SETTINGS = {
122
"cherry_blossom": "What is in the picture?",
123
}),
124
auto_cls=AutoModelForImageTextToText,
125
- postprocess_inputs=model_utils.cast_dtype_post_processor(
126
- "pixel_values"
127
- ),
125
vllm_output_post_proc=model_utils.paligemma_vllm_to_hf_output,
126
dtype="bfloat16",
127
marks=[pytest.mark.skip(reason="vLLM does not support PrefixLM attention mask")], # noqa: E501
@@ -179,7 +176,6 @@ VLM_TEST_SETTINGS = {
176
# "cherry_blossom": "<vlm_image>Please infer the season with reason.", # noqa: E501
177
# }),
178
# multi_image_prompt="<vlm_image><vlm_image>Describe the two images shortly.", # noqa: E501
182
- # postprocess_inputs=model_utils.cast_dtype_post_processor("pixel_values"), # noqa: E501
179
# stop_str=["<|im_end|>"],
180
# image_size_factors=[(0.10, 0.15)],
181
# max_tokens=64,
@@ -200,9 +196,6 @@ VLM_TEST_SETTINGS = {
196
max_model_len=4096,
197
max_num_seqs=2,
198
auto_cls=AutoModelForImageTextToText,
203
- postprocess_inputs=model_utils.cast_dtype_post_processor(
204
- "pixel_values"
205
- ),
199
# For chameleon, we only compare the sequences
200
vllm_output_post_proc = lambda vllm_output, model: vllm_output[:2],
201
hf_output_post_proc = lambda hf_output, model: hf_output[:2],
@@ -222,7 +215,6 @@ VLM_TEST_SETTINGS = {
215
}),
216
multi_image_prompt="image_1:<image>\nimage_2:<image>\nWhich image can we see the car and the tower?", # noqa: E501
217
patch_hf_runner=model_utils.deepseekvl2_patch_hf_runner,
225
- postprocess_inputs=model_utils.cast_dtype_post_processor("images"),
218
hf_output_post_proc=model_utils.deepseekvl2_trunc_hf_output,
219
stop_str=["<|end▁of▁sentence|>", "<|begin▁of▁sentence|>"], # noqa: E501
220
image_size_factors=[(), (1.0, ), (1.0, 1.0, 1.0), (0.1, 0.5, 1.0)],
@@ -258,7 +250,6 @@ VLM_TEST_SETTINGS = {
250
max_model_len=4096,
251
max_num_seqs=2,
252
auto_cls=AutoModelForImageTextToText,
261
- dtype="bfloat16",
253
vllm_runner_kwargs={"mm_processor_kwargs": {"do_pan_and_scan": True}},
254
patch_hf_runner=model_utils.gemma3_patch_hf_runner,
255
),
@@ -272,7 +263,6 @@ VLM_TEST_SETTINGS = {
263
}),
264
max_model_len=2048,
265
max_num_seqs=2,
275
- dtype="bfloat16",
266
get_stop_token_ids=lambda tok: [151329, 151336, 151338],
267
patch_hf_runner=model_utils.glm4v_patch_hf_runner,
268
# The image embeddings match with HF but the outputs of the language
@@ -295,7 +285,6 @@ VLM_TEST_SETTINGS = {
285
}),
286
multi_image_prompt="Image-1: <image>\nImage-2: <image>\nDescribe the two images in short.", # noqa: E501
287
max_model_len=8192,
298
- dtype="bfloat16",
288
use_tokenizer_eos=True,
289
num_logprobs=10,
290
patch_hf_runner=model_utils.h2ovl_patch_hf_runner,
@@ -324,10 +313,6 @@ VLM_TEST_SETTINGS = {
313
}),
314
multi_image_prompt="Image-1: <image>\nImage-2: <image>\nDescribe the two images in short.", # noqa: E501
315
max_model_len=4096,
327
- # NOTE: Mono-InternVL-2B doesn't work with fp16,
328
- # it will result NaN during inference.
329
- # See: https://huggingface.co/OpenGVLab/Mono-InternVL-2B/discussions/9
330
- dtype="bfloat16",
316
use_tokenizer_eos=True,
317
patch_hf_runner=model_utils.internvl_patch_hf_runner,
318
),
@@ -351,9 +336,6 @@ VLM_TEST_SETTINGS = {
336
prompt_formatter=lambda vid_prompt: f"<|im_start|>user\n{vid_prompt}<|im_end|>\n<|im_start|>assistant\n", # noqa: E501
337
num_video_frames=16,
338
max_model_len=16384,
354
- postprocess_inputs=model_utils.cast_dtype_post_processor(
355
- "pixel_values_videos"
356
- ),
339
auto_cls=AutoModelForVision2Seq,
340
vllm_output_post_proc=model_utils.llava_onevision_vllm_to_hf_output,
341
custom_test_opts=[CustomTestOptions(
@@ -378,9 +360,6 @@ VLM_TEST_SETTINGS = {
360
test_type=(VLMTestType.IMAGE, VLMTestType.MULTI_IMAGE),
361
prompt_formatter=lambda img_prompt: f"<|start_header_id|>user<|end_header_id|>\n\n{img_prompt}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n", # noqa: E501
362
max_model_len=4096,
381
- postprocess_inputs=model_utils.cast_dtype_post_processor(
382
- "pixel_values"
383
- ),
363
get_stop_token_ids=lambda tok: [128009],
364
auto_cls=AutoModelForImageTextToText,
365
vllm_output_post_proc=model_utils.mantis_vllm_to_hf_output,
@@ -400,8 +379,8 @@ VLM_TEST_SETTINGS = {
379
max_model_len=4096,
380
max_num_seqs=2,
381
get_stop_token_ids=lambda tok: [tok.eos_id, tok.eot_id],
403
- postprocess_inputs=model_utils.wrap_inputs_post_processor,
382
hf_output_post_proc=model_utils.minicpmv_trunc_hf_output,
383
+ patch_hf_runner=model_utils.minicpmv_25_patch_hf_runner,
384
),
385
"minicpmo_26": VLMTestInfo(
386
models=["openbmb/MiniCPM-o-2_6"],
@@ -411,11 +390,8 @@ VLM_TEST_SETTINGS = {
390
max_model_len=4096,
391
max_num_seqs=2,
392
get_stop_token_ids=lambda tok: tok.convert_tokens_to_ids(['<|im_end|>', '<|endoftext|>']), # noqa: E501
414
- postprocess_inputs=model_utils.ignore_inputs_post_processor(
415
- "image_sizes"
416
- ),
393
hf_output_post_proc=model_utils.minicpmv_trunc_hf_output,
418
- patch_hf_runner=model_utils.minicpmo_patch_hf_runner
394
+ patch_hf_runner=model_utils.minicpmo_26_patch_hf_runner,
395
),
396
"minicpmv_26": VLMTestInfo(
397
models=["openbmb/MiniCPM-V-2_6"],
@@ -425,10 +401,8 @@ VLM_TEST_SETTINGS = {
401
max_model_len=4096,
402
max_num_seqs=2,
403
get_stop_token_ids=lambda tok: tok.convert_tokens_to_ids(['<|im_end|>', '<|endoftext|>']), # noqa: E501
428
- postprocess_inputs=model_utils.ignore_inputs_post_processor(
429
- "image_sizes"
430
- ),
404
hf_output_post_proc=model_utils.minicpmv_trunc_hf_output,
405
+ patch_hf_runner=model_utils.minicpmv_26_patch_hf_runner,
406
),
407
"molmo": VLMTestInfo(
408
models=["allenai/Molmo-7B-D-0924"],
@@ -437,7 +411,6 @@ VLM_TEST_SETTINGS = {
411
max_model_len=4096,
412
max_num_seqs=2,
413
patch_hf_runner=model_utils.molmo_patch_hf_runner,
440
- postprocess_inputs=model_utils.molmo_post_processor,
414
),
415
# Tests for phi3v currently live in another file because of a bug in
416
# transformers. Once this issue is fixed, we can enable them here instead.
@@ -482,9 +455,6 @@ VLM_TEST_SETTINGS = {
455
prompt_formatter=lambda img_prompt: f"USER: {img_prompt}\nASSISTANT:",
456
max_model_len=4096,
457
auto_cls=AutoModelForImageTextToText,
485
- postprocess_inputs=model_utils.cast_dtype_post_processor(
486
- "pixel_values"
487
- ),
458
vllm_output_post_proc = lambda vllm_output, model: vllm_output[:2],
459
hf_output_post_proc = lambda hf_output, model: hf_output[:2],
460
comparator=check_outputs_equal,
@@ -529,9 +499,6 @@ VLM_TEST_SETTINGS = {
499
test_type=VLMTestType.CUSTOM_INPUTS,
500
max_model_len=16384,
501
max_num_seqs=2,
532
- postprocess_inputs=model_utils.cast_dtype_post_processor(
533
- "pixel_values"
534
- ),
502
auto_cls=AutoModelForVision2Seq,
503
vllm_output_post_proc=model_utils.llava_onevision_vllm_to_hf_output,
504
custom_test_opts=[CustomTestOptions(
tests/models/decoder_only/vision_language/vlm_utils/core.py
-3
@@ -4,7 +4,6 @@ from typing import Any, Callable, Optional, Union
4
5
import torch
6
from PIL.Image import Image
7
-from transformers import BatchEncoding
7
from transformers.models.auto.auto_factory import _BaseAutoModelClass
8
9
from vllm.config import TaskOption
@@ -31,7 +30,6 @@ def run_test(
30
vllm_output_post_proc: Optional[Callable[[RunnerOutput, str], Any]],
31
auto_cls: type[_BaseAutoModelClass],
32
use_tokenizer_eos: bool,
34
- postprocess_inputs: Callable[[BatchEncoding], BatchEncoding],
33
comparator: Callable[..., None],
34
get_stop_token_ids: Optional[Callable[[AnyTokenizer], list[int]]],
35
stop_str: Optional[list[str]],
@@ -101,7 +99,6 @@ def run_test(
99
hf_model = hf_runner(model,
100
dtype=dtype,
101
auto_cls=auto_cls,
104
- postprocess_inputs=postprocess_inputs,
102
model_kwargs=hf_model_kwargs)
103
104
# Some models need to patch things like the model processor, e.g., internvl
tests/models/decoder_only/vision_language/vlm_utils/model_utils.py
+49
-42
@@ -6,16 +6,15 @@ typically specific to a small subset of models.
6
import re
7
import types
8
from pathlib import PosixPath
9
-from typing import Callable, Optional, Union
9
+from typing import Optional, Union
10
11
import torch
12
from PIL.Image import Image
13
-from transformers import (AutoConfig, AutoTokenizer, BatchEncoding,
13
+from transformers import (AutoConfig, AutoTokenizer, BatchFeature,
14
GenerationConfig)
15
16
from vllm.sequence import SampleLogprobs
17
from vllm.transformers_utils.tokenizer import patch_padding_side
18
-from vllm.utils import STR_DTYPE_TO_TORCH_DTYPE
18
19
from .....conftest import HfRunner, ImageAsset, _ImageAssets
20
from .types import RunnerOutput
@@ -211,40 +210,6 @@ def get_llava_embeddings(image_assets: _ImageAssets):
210
return [asset.image_embeds for asset in image_assets]
211
212
214
-####### postprocessors to run on HF BatchEncoding
215
-def cast_dtype_post_processor(
216
- hf_inp_key: str) -> Callable[[BatchEncoding, str], BatchEncoding]:
217
- """Gets a handle to a post processor which converts a given key into a
218
- target data type."""
219
-
220
- def process(hf_inputs: BatchEncoding, dtype: str):
221
- torch_dtype = STR_DTYPE_TO_TORCH_DTYPE[dtype]
222
- hf_inputs[hf_inp_key] = hf_inputs[hf_inp_key].to(torch_dtype)
223
- return hf_inputs
224
-
225
- return process
226
-
227
-
228
-def ignore_inputs_post_processor(
229
- hf_inp_key: str) -> Callable[[BatchEncoding, str], BatchEncoding]:
230
- """Gets a handle to a post processor which ignores a given key."""
231
-
232
- def process(hf_inputs: BatchEncoding, dtype: str):
233
- del hf_inputs[hf_inp_key]
234
- return hf_inputs
235
-
236
- return process
237
-
238
-
239
-def wrap_inputs_post_processor(hf_inputs: BatchEncoding, dtype: str):
240
- return {"model_inputs": hf_inputs}
241
-
242
-
243
-def molmo_post_processor(hf_inputs: BatchEncoding, dtype: str):
244
- hf_inputs = cast_dtype_post_processor("images")(hf_inputs, dtype)
245
- return {k: v.unsqueeze(0) for k, v in hf_inputs.items()}
246
-
247
-
213
####### Prompt path encoders for models that need models on disk
214
def qwen_prompt_path_encoder(
215
tmp_path: PosixPath, prompt: str, assets: Union[list[ImageAsset],
@@ -295,8 +260,7 @@ def deepseekvl2_patch_hf_runner(hf_model: HfRunner) -> HfRunner:
260
for k in inputs.keys() # noqa
261
if k not in ("seq_lens", "sft_format")
262
}
298
- inputs = BatchEncoding(data=inputs, tensor_type="pt")
299
- return inputs
263
+ return BatchFeature(data=inputs, tensor_type="pt")
264
265
hf_model.processor = processor
266
hf_model.model.get_output_embeddings = lambda: \
@@ -529,10 +493,52 @@ def mantis_patch_hf_runner(hf_model: HfRunner) -> HfRunner:
493
return hf_model
494
495
532
-def minicpmo_patch_hf_runner(hf_model: HfRunner) -> HfRunner:
496
+def minicpmv_25_patch_hf_runner(hf_model: HfRunner) -> HfRunner:
497
orig_generate = hf_model.model.generate
498
535
- def _generate(self, *args, **kwargs):
499
+ def _generate(
500
+ self,
501
+ *args,
502
+ input_ids=None,
503
+ pixel_values=None,
504
+ image_sizes=None,
505
+ image_bound=None,
506
+ tgt_sizes=None,
507
+ **kwargs,
508
+ ):
509
+ model_inputs = {
510
+ "input_ids": input_ids,
511
+ "pixel_values": pixel_values,
512
+ "image_sizes": image_sizes,
513
+ "image_bound": image_bound,
514
+ "tgt_sizes": tgt_sizes,
515
+ }
516
+ for k in list(model_inputs.keys()):
517
+ if model_inputs[k] is None:
518
+ model_inputs.pop(k)
519
+
520
+ return orig_generate(model_inputs, *args, decode_text=False, **kwargs)
521
+
522
+ hf_model.model.generate = types.MethodType(_generate, hf_model.model)
523
+
524
+ return hf_model
525
+
526
+
527
+def minicpmo_26_patch_hf_runner(hf_model: HfRunner) -> HfRunner:
528
+ orig_generate = hf_model.model.generate
529
+
530
+ def _generate(self, *args, image_sizes=None, **kwargs):
531
+ return orig_generate(*args, decode_text=False, **kwargs)
532
+
533
+ hf_model.model.generate = types.MethodType(_generate, hf_model.model)
534
+
535
+ return hf_model
536
+
537
+
538
+def minicpmv_26_patch_hf_runner(hf_model: HfRunner) -> HfRunner:
539
+ orig_generate = hf_model.model.generate
540
+
541
+ def _generate(self, *args, image_sizes=None, **kwargs):
542
return orig_generate(*args, decode_text=False, **kwargs)
543
544
hf_model.model.generate = types.MethodType(_generate, hf_model.model)
@@ -551,10 +557,11 @@ def molmo_patch_hf_runner(hf_model: HfRunner) -> HfRunner:
557
558
def _generate(self, max_new_tokens=None, do_sample=None, **kwargs):
559
batch = {
554
- k: kwargs.pop(k)
560
+ k: kwargs.pop(k).unsqueeze(0)
561
for k in ("input_ids", "images", "image_input_idx", "image_masks")
562
if k in kwargs
563
}
564
+ batch = BatchFeature(batch).to(dtype=self.dtype)
565
566
return self.generate_from_batch(
567
batch,
tests/models/decoder_only/vision_language/vlm_utils/types.py
+2
-9
@@ -8,13 +8,12 @@ from typing import Any, Callable, NamedTuple, Optional, Union
8
import torch
9
from PIL.Image import Image
10
from pytest import MarkDecorator
11
-from transformers import AutoModelForCausalLM, BatchEncoding
11
+from transformers import AutoModelForCausalLM
12
from transformers.models.auto.auto_factory import _BaseAutoModelClass
13
14
from vllm.config import TaskOption
15
from vllm.sequence import SampleLogprobs
16
from vllm.transformers_utils.tokenizer import AnyTokenizer
17
-from vllm.utils import identity
17
18
from .....conftest import IMAGE_ASSETS, HfRunner, ImageAsset, _ImageAssets
19
from ....utils import check_logprobs_close
@@ -110,11 +109,6 @@ class VLMTestInfo(NamedTuple):
109
# Indicates we should explicitly pass the EOS from the tokenizer
110
use_tokenizer_eos: bool = False
111
auto_cls: type[_BaseAutoModelClass] = AutoModelForCausalLM
113
- # Callable to pass to the HF runner to run on inputs; for now, we also pass
114
- # the data type to input post processing, because almost all of the uses of
115
- # postprocess_inputs are to fix the data types of BatchEncoding values.
116
- postprocess_inputs: Callable[[BatchEncoding, str],
117
- BatchEncoding] = identity
112
patch_hf_runner: Optional[Callable[[HfRunner], HfRunner]] = None
113
114
# Post processors that if defined, will run oun the outputs of the
@@ -130,7 +124,7 @@ class VLMTestInfo(NamedTuple):
124
# is all combinations of .models + all fields below
125
max_tokens: Union[int, tuple[int]] = 128
126
num_logprobs: Union[int, tuple[int]] = 5
133
- dtype: Union[str, Iterable[str]] = "half"
127
+ dtype: Union[str, Union[list[str], tuple[str, ...]]] = "auto"
128
distributed_executor_backend: Optional[Union[str, Iterable[str]]] = None
129
# Only expanded in video tests
130
num_video_frames: Union[int, tuple[int]] = 16
@@ -171,7 +165,6 @@ class VLMTestInfo(NamedTuple):
165
"vllm_output_post_proc": self.vllm_output_post_proc,
166
"auto_cls": self.auto_cls,
167
"use_tokenizer_eos": self.use_tokenizer_eos,
174
- "postprocess_inputs": self.postprocess_inputs,
168
"comparator": self.comparator,
169
"get_stop_token_ids": self.get_stop_token_ids,
170
"hf_model_kwargs": self.hf_model_kwargs,
tests/models/embedding/vision_language/test_dse_qwen2_vl.py
+28
-24
@@ -1,12 +1,12 @@
1
# SPDX-License-Identifier: Apache-2.0
2
3
-from functools import partial
3
from typing import Callable
4
5
import pytest
6
import torch
7
+import torch.nn.functional as F
8
from PIL import Image
9
-from transformers import BatchEncoding, Qwen2VLForConditionalGeneration
9
+from transformers import Qwen2VLForConditionalGeneration
10
11
from ....conftest import IMAGE_ASSETS, HfRunner, PromptImageInput, VllmRunner
12
from ....utils import large_gpu_test
@@ -75,10 +75,6 @@ def apply_chat_template_and_add_eos(
75
return prompt
76
77
78
-def postprocess_inputs(hf_model: HfRunner, inputs: BatchEncoding, **kwargs):
79
- return hf_model.model.prepare_inputs_for_generation(**inputs, **kwargs)
80
-
81
-
78
def _run_test(
79
hf_runner: type[HfRunner],
80
vllm_runner: type[VllmRunner],
@@ -118,14 +114,8 @@ def _run_test(
114
with hf_runner(model,
115
dtype=dtype,
116
auto_cls=Qwen2VLForConditionalGeneration) as hf_model:
121
- hf_model.postprocess_inputs = partial(
122
- postprocess_inputs,
123
- hf_model,
124
- cache_position=torch.arange(
125
- 0,
126
- 1, # 1 for batch size
127
- requires_grad=False),
128
- use_cache=False)
117
+
118
+ prompts = []
119
for text, image, embed_text in zip(input_texts, input_images,
120
embed_texts):
121
# dse requires non-standard input processing
@@ -133,20 +123,34 @@ def _run_test(
123
messages = get_messages(image, text, embed_text)
124
prompt = apply_chat_template_and_add_eos(
125
messages, hf_model.processor.apply_chat_template)
136
- inputs = hf_model.get_inputs(
137
- prompts=[[prompt]],
138
- images=[[image]],
139
- )
140
- with torch.no_grad():
126
+
127
+ prompts.append(prompt)
128
+
129
+ all_inputs = hf_model.get_inputs(
130
+ prompts=prompts,
131
+ images=input_images,
132
+ )
133
+
134
+ with torch.no_grad():
135
+ all_outputs = []
136
+ for inputs in all_inputs:
137
+ inputs = hf_model.model.prepare_inputs_for_generation(
138
+ **inputs,
139
+ cache_position=torch.arange(1), # 1 for batch size
140
+ use_cache=False,
141
+ )
142
outputs = hf_model.model(
142
- **hf_model.wrap_device(inputs[0],
143
- device=hf_model.model.device.type),
143
+ **hf_model.wrap_device(inputs),
144
return_dict=True,
145
output_hidden_states=True,
146
)
147
- pooled_output = torch.nn.functional.normalize(
148
- outputs.hidden_states[-1][0, -1], p=2, dim=-1)
149
- hf_outputs.append(pooled_output.tolist())
147
+ pooled_output = F.normalize(outputs.hidden_states[-1][0, -1],
148
+ p=2,
149
+ dim=-1)
150
+
151
+ all_outputs.append(pooled_output.tolist())
152
+
153
+ hf_outputs = all_outputs
154
155
check_embeddings_close(
156
embeddings_0_lst=hf_outputs,
tests/models/embedding/vision_language/test_llava_next.py
+1
-2
@@ -86,8 +86,7 @@ def _run_test(
86
for inputs in all_inputs:
87
# Based on: https://huggingface.co/royokong/e5-v
88
outputs = hf_model.model(
89
- **hf_model.wrap_device(inputs,
90
- device=hf_model.model.device.type),
89
+ **hf_model.wrap_device(inputs),
90
return_dict=True,
91
output_hidden_states=True,
92
)
tests/models/embedding/vision_language/test_phi3v.py
+1
-2
@@ -53,8 +53,7 @@ def _run_test(
53
for inputs in all_inputs:
54
# Based on: https://github.com/TIGER-AI-Lab/VLM2Vec/blob/db3b951bccabba220c1f53ab46a734e50dd2fc08/src/model.py
55
outputs = hf_model.model(
56
- **hf_model.wrap_device(inputs,
57
- device=hf_model.model.device.type),
56
+ **hf_model.wrap_device(inputs),
57
return_dict=True,
58
output_hidden_states=True,
59
)
tests/models/encoder_decoder/vision_language/test_mllama.py
+1
-6
@@ -4,8 +4,7 @@ from typing import Optional, overload
4
5
import pytest
6
import torch
7
-from transformers import (AutoConfig, AutoModelForImageTextToText,
8
- AutoTokenizer, BatchEncoding)
7
+from transformers import AutoConfig, AutoModelForImageTextToText, AutoTokenizer
8
9
from vllm import LLM, SamplingParams
10
from vllm.attention.backends.flash_attn import FlashAttentionMetadata
@@ -227,13 +226,9 @@ def _run_test(
226
for prompts, images in inputs
227
]
228
230
- def process(hf_inputs: BatchEncoding, **kwargs):
231
- return hf_inputs
232
-
229
with hf_runner(model,
230
dtype=dtype,
231
model_kwargs={"device_map": "auto"},
236
- postprocess_inputs=process,
232
auto_cls=AutoModelForImageTextToText) as hf_model:
233
hf_outputs_per_image = [
234
hf_model.generate_greedy_logprobs_limit(prompts,
tests/models/utils.py
+4
-7
@@ -2,7 +2,7 @@
2
3
import warnings
4
from collections.abc import Sequence
5
-from typing import Optional, Union
5
+from typing import Any, Optional, Union
6
7
import torch
8
@@ -254,9 +254,9 @@ def check_logprobs_close(
254
def build_model_context(
255
model_id: str,
256
task: TaskOption = "auto",
257
- dtype: Optional[Union[str, torch.dtype]] = None,
258
- mm_processor_kwargs: Optional[dict] = None,
259
- limit_mm_per_prompt: Optional[dict] = None,
257
+ dtype: Union[str, torch.dtype] = "auto",
258
+ mm_processor_kwargs: Optional[dict[str, Any]] = None,
259
+ limit_mm_per_prompt: Optional[dict[str, int]] = None,
260
disable_mm_preprocessor_cache: bool = True,
261
):
262
"""Creates an InputContext for a given model.
@@ -274,9 +274,6 @@ def build_model_context(
274
model_info.check_available_online(on_fail="skip")
275
model_info.check_transformers_version(on_fail="skip")
276
277
- if dtype is None:
278
- dtype = "half"
279
-
277
model_config = ModelConfig(
278
model_id,
279
task=task,
tests/multimodal/test_processing.py
+3
-3
@@ -853,7 +853,7 @@ def test_limit_mm_per_prompt_dummy(model_id, limit, num_supported, is_valid):
853
tokenizer_mode="auto",
854
trust_remote_code=False,
855
seed=0,
856
- dtype="half",
856
+ dtype="auto",
857
revision=None,
858
limit_mm_per_prompt=limit_mm_per_prompt,
859
)
@@ -892,7 +892,7 @@ def test_limit_mm_per_prompt_apply(model_id, num_images, limit, is_valid):
892
tokenizer_mode="auto",
893
trust_remote_code=False,
894
seed=0,
895
- dtype="half",
895
+ dtype="auto",
896
revision=None,
897
limit_mm_per_prompt=limit_mm_per_prompt,
898
)
@@ -965,7 +965,7 @@ def test_hf_processor_kwargs(model_id, call_kwargs, expected_kwargs):
965
tokenizer_mode="auto",
966
trust_remote_code=False,
967
seed=0,
968
- dtype="half",
968
+ dtype="auto",
969
revision=None,
970
)
971
tests/tensorizer_loader/test_tensorizer.py
+2
-2
@@ -166,7 +166,7 @@ def test_vllm_model_can_load_with_lora(vllm_runner, tmp_path):
166
test_prompts = multilora_inference.create_test_prompts(lora_path)
167
168
# Serialize model before deserializing and binding LoRA adapters
169
- with vllm_runner(model_ref, ) as vllm_model:
169
+ with vllm_runner(model_ref) as vllm_model:
170
model_path = tmp_path / (model_ref + ".tensors")
171
172
vllm_model.apply_model(
@@ -208,7 +208,7 @@ def test_load_without_tensorizer_load_format(vllm_runner):
208
@pytest.mark.skipif(not is_curl_installed(), reason="cURL is not installed")
209
def test_openai_apiserver_with_tensorizer(vllm_runner, tmp_path):
210
## Serialize model
211
- with vllm_runner(model_ref, ) as vllm_model:
211
+ with vllm_runner(model_ref) as vllm_model:
212
model_path = tmp_path / (model_ref + ".tensors")
213
214
vllm_model.apply_model(
tests/v1/engine/test_llm_engine.py
+1
-1
@@ -50,7 +50,7 @@ def _get_test_sampling_params(
50
"""Generate random sampling params for a batch."""
51
52
def get_mostly_n_gt1() -> int:
53
- """Mostly n \in [2,20], ~1/3 n=1"""
53
+ r"""Mostly n \in [2,20], ~1/3 n=1"""
54
x = random.randint(0, 28)
55
if x < 10:
56
return 1
vllm/config.py
+11
-11
@@ -347,7 +347,7 @@ class ModelConfig:
347
self.encoder_config = self._get_encoder_config()
348
self.hf_image_processor_config = get_hf_image_processor_config(
349
self.model, revision)
350
- self.dtype = _get_and_verify_dtype(self.hf_text_config, dtype)
350
+ self.dtype = _get_and_verify_dtype(self.hf_config, dtype)
351
self.use_async_output_proc = use_async_output_proc
352
self.mm_processor_kwargs = mm_processor_kwargs
353
self.disable_mm_preprocessor_cache = disable_mm_preprocessor_cache
@@ -2526,6 +2526,14 @@ def _get_and_verify_dtype(
2526
# NOTE: getattr(config, "torch_dtype", torch.float32) is not correct
2527
# because config.torch_dtype can be None.
2528
config_dtype = getattr(config, "torch_dtype", None)
2529
+
2530
+ # Fallbacks for multi-modal models if the root config
2531
+ # does not define torch_dtype
2532
+ if config_dtype is None and hasattr(config, "text_config"):
2533
+ config_dtype = getattr(config.text_config, "torch_dtype", None)
2534
+ if config_dtype is None and hasattr(config, "vision_config"):
2535
+ config_dtype = getattr(config.vision_config, "torch_dtype", None)
2536
+
2537
if config_dtype is None:
2538
config_dtype = torch.float32
2539
@@ -2533,16 +2541,8 @@ def _get_and_verify_dtype(
2541
dtype = dtype.lower()
2542
if dtype == "auto":
2543
if config_dtype == torch.float32:
2536
- if config.model_type in ("gemma2", "gemma3", "gemma3_text"):
2537
- logger.info(
2538
- "For Gemma 2 and 3, we downcast float32 to bfloat16 "
2539
- "instead of float16 by default. Please specify `dtype` "
2540
- "if you want to use float16.")
2541
- torch_dtype = torch.bfloat16
2542
- else:
2543
- # Following the common practice, we use float16 for float32
2544
- # models.
2545
- torch_dtype = torch.float16
2544
+ # Following common practice, we use float16 for float32 models
2545
+ torch_dtype = torch.float16
2546
else:
2547
torch_dtype = config_dtype
2548