@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 27f4c2fd46
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 11, 21:15 UTC

[Renderer] Separate out `RendererConfig` from `ModelConfig` (#30145)

Signed-off-by: DarkLight1337 <tlleungac@connect.ust.hk>

Cyrus Leung committed Dec 7, 2025 at 15:15 UTC 27f4c2fd46b99778d7ea19dfe7751fbaab615177
105 files changed +971 -799
docs/contributing/model/transcription.md
+6 -6
@@ -22,7 +22,7 @@ Declare supported languages and capabilities:
22 import torch
23 from torch import nn
24
25 - from vllm.config import ModelConfig, SpeechToTextConfig
25 + from vllm.config import RendererConfig, SpeechToTextConfig
26 from vllm.inputs.data import PromptType
27 from vllm.model_executor.models.interfaces import SupportsTranscription
28
@@ -52,7 +52,7 @@ This is for controlling general behavior of the API when serving your model:
52 @classmethod
53 def get_speech_to_text_config(
54 cls,
55 - model_config: ModelConfig,
55 + renderer_config: RendererConfig,
56 task_type: Literal["transcribe", "translate"],
57 ) -> SpeechToTextConfig:
58 return SpeechToTextConfig(
@@ -83,7 +83,7 @@ Return a dict containing `multi_modal_data` with the audio, and either a `prompt
83 cls,
84 audio: np.ndarray,
85 stt_config: SpeechToTextConfig,
86 - model_config: ModelConfig,
86 + renderer_config: RendererConfig,
87 language: str | None,
88 task_type: Literal["transcribe", "translate"],
89 request_prompt: str,
@@ -120,7 +120,7 @@ Return a dict with separate `encoder_prompt` and `decoder_prompt` entries:
120 cls,
121 audio: np.ndarray,
122 stt_config: SpeechToTextConfig,
123 - model_config: ModelConfig,
123 + renderer_config: RendererConfig,
124 language: str | None,
125 task_type: Literal["transcribe", "translate"],
126 request_prompt: str,
@@ -183,7 +183,7 @@ Provide a fast duration→token estimate to improve streaming usage statistics:
183 cls,
184 audio_duration_s: float,
185 stt_config: SpeechToTextConfig,
186 - model_config: ModelConfig,
186 + renderer_config: RendererConfig,
187 ) -> int | None:
188 # Return None if unknown; otherwise return an estimate.
189 return int(audio_duration_s * stt_config.sample_rate // 320) # example
@@ -216,7 +216,7 @@ Relevant server logic:
216 prompt = self.model_cls.get_generation_prompt(
217 audio=chunk,
218 stt_config=self.asr_config,
219 - model_config=self.model_config,
219 + renderer_config=self.renderer_config,
220 language=language,
221 task_type=self.task_type,
222 request_prompt=request.prompt,
tests/compile/distributed/test_sequence_parallelism.py
+2
@@ -17,6 +17,7 @@ from vllm.config import (
17 DeviceConfig,
18 ModelConfig,
19 PassConfig,
20 + RendererConfig,
21 VllmConfig,
22 get_current_vllm_config,
23 set_current_vllm_config,
@@ -276,6 +277,7 @@ def sequence_parallelism_pass_on_test_model(
277
278 vllm_config = VllmConfig(
279 model_config=model_config,
280 + renderer_config=RendererConfig(model_config=model_config),
281 device_config=device_config,
282 compilation_config=compilation_config,
283 )
tests/compile/test_functionalization.py
+5 -1
@@ -15,6 +15,7 @@ from vllm.config import (
15 CompilationConfig,
16 ModelConfig,
17 PassConfig,
18 + RendererConfig,
19 VllmConfig,
20 set_current_vllm_config,
21 )
@@ -219,8 +220,11 @@ def test_fix_functionalization(
220 torch.set_default_device("cuda")
221 torch.set_default_dtype(dtype)
222
223 + model_config = ModelConfig(dtype=dtype)
224 +
225 vllm_config = VllmConfig(
223 - model_config=ModelConfig(dtype=dtype),
226 + model_config=model_config,
227 + renderer_config=RendererConfig(model_config=model_config),
228 compilation_config=CompilationConfig(
229 custom_ops=["all"],
230 pass_config=PassConfig(
tests/compile/test_fusion.py
+5 -1
@@ -15,6 +15,7 @@ from vllm.config import (
15 CompilationMode,
16 ModelConfig,
17 PassConfig,
18 + RendererConfig,
19 VllmConfig,
20 )
21 from vllm.model_executor.layers.layernorm import RMSNorm
@@ -154,8 +155,11 @@ def test_fusion_rmsnorm_quant(
155 custom_ops.append("+rms_norm")
156 if enable_quant_fp8_custom_op:
157 custom_ops.append("+quant_fp8")
158 +
159 + model_config = ModelConfig(dtype=dtype)
160 vllm_config = VllmConfig(
158 - model_config=ModelConfig(dtype=dtype),
161 + model_config=model_config,
162 + renderer_config=RendererConfig(model_config=model_config),
163 compilation_config=CompilationConfig(
164 mode=CompilationMode.VLLM_COMPILE,
165 custom_ops=custom_ops,
tests/compile/test_fusion_attn.py
+2
@@ -24,6 +24,7 @@ from vllm.config import (
24 CompilationMode,
25 ModelConfig,
26 PassConfig,
27 + RendererConfig,
28 SchedulerConfig,
29 VllmConfig,
30 set_current_vllm_config,
@@ -325,6 +326,7 @@ def test_attention_quant_pattern(
326 )
327 vllm_config = VllmConfig(
328 model_config=model_config,
329 + renderer_config=RendererConfig(model_config=model_config),
330 scheduler_config=SchedulerConfig(
331 max_num_seqs=1024,
332 max_model_len=model_config.max_model_len,
tests/compile/test_pass_manager.py
+6 -2
@@ -7,7 +7,7 @@ import torch
7
8 from vllm.compilation.inductor_pass import CallableInductorPass, InductorPass
9 from vllm.compilation.pass_manager import PostGradPassManager
10 -from vllm.config import ModelConfig, VllmConfig
10 +from vllm.config import ModelConfig, RendererConfig, VllmConfig
11
12
13 # dummy custom pass that doesn't inherit
@@ -43,7 +43,11 @@ class ProperPass(InductorPass):
43 )
44 def test_pass_manager_uuid(callable):
45 # Some passes need dtype to be set
46 - config = VllmConfig(model_config=ModelConfig(dtype=torch.bfloat16))
46 + model_config = ModelConfig(dtype=torch.bfloat16)
47 + config = VllmConfig(
48 + model_config=model_config,
49 + renderer_config=RendererConfig(model_config=model_config),
50 + )
51
52 pass_manager = PostGradPassManager()
53 pass_manager.configure(config)
tests/compile/test_qk_norm_rope_fusion.py
+4 -1
@@ -19,6 +19,7 @@ from vllm.config import (
19 CompilationMode,
20 ModelConfig,
21 PassConfig,
22 + RendererConfig,
23 VllmConfig,
24 set_current_vllm_config,
25 )
@@ -133,8 +134,10 @@ def test_qk_norm_rope_fusion(
134 if enable_rope_custom_op:
135 custom_ops.append("+rotary_embedding")
136
137 + model_config = ModelConfig(dtype=dtype)
138 vllm_config = VllmConfig(
137 - model_config=ModelConfig(dtype=dtype),
139 + model_config=model_config,
140 + renderer_config=RendererConfig(model_config=model_config),
141 compilation_config=CompilationConfig(
142 mode=CompilationMode.VLLM_COMPILE,
143 custom_ops=custom_ops,
tests/distributed/test_kvlayout.py
+3
@@ -5,6 +5,7 @@ from vllm.config import (
5 DeviceConfig,
6 KVTransferConfig,
7 ModelConfig,
8 + RendererConfig,
9 VllmConfig,
10 set_current_vllm_config,
11 )
@@ -47,6 +48,7 @@ def test_get_kv_connector_cache_layout_with_nixl_connector():
48 vllm_config = VllmConfig(
49 device_config=DeviceConfig("cpu"),
50 model_config=model_config,
51 + renderer_config=RendererConfig(model_config=model_config),
52 kv_transfer_config=kv_transfer_config,
53 )
54 with set_current_vllm_config(vllm_config):
@@ -70,6 +72,7 @@ def test_get_kv_connector_cache_layout_with_multi_connector():
72 vllm_config = VllmConfig(
73 device_config=DeviceConfig("cpu"),
74 model_config=model_config,
75 + renderer_config=RendererConfig(model_config=model_config),
76 kv_transfer_config=kv_transfer_config,
77 )
78 with set_current_vllm_config(vllm_config):
tests/entrypoints/openai/test_chat_template.py
+4 -18
@@ -3,7 +3,6 @@
3
4 import pytest
5
6 -from vllm.config import ModelConfig
6 from vllm.entrypoints.chat_utils import apply_hf_chat_template, load_chat_template
7 from vllm.entrypoints.openai.protocol import ChatCompletionRequest
8 from vllm.tokenizers import get_tokenizer
@@ -107,24 +106,11 @@ def test_get_gen_prompt(
106 model_info = HF_EXAMPLE_MODELS.find_hf_info(model)
107 model_info.check_available_online(on_fail="skip")
108
110 - model_config = ModelConfig(
111 - model,
112 - tokenizer=model_info.tokenizer or model,
113 - tokenizer_mode=model_info.tokenizer_mode,
114 - trust_remote_code=model_info.trust_remote_code,
115 - revision=model_info.revision,
116 - hf_overrides=model_info.hf_overrides,
117 - skip_tokenizer_init=model_info.require_embed_inputs,
118 - enable_prompt_embeds=model_info.require_embed_inputs,
119 - enable_mm_embeds=model_info.require_embed_inputs,
120 - enforce_eager=model_info.enforce_eager,
121 - dtype=model_info.dtype,
122 - )
109 + renderer_config = model_info.build_renderer_config(model)
110
124 - # Initialize the tokenizer
111 tokenizer = get_tokenizer(
126 - tokenizer_name=model_config.tokenizer,
127 - trust_remote_code=model_config.trust_remote_code,
112 + renderer_config.tokenizer,
113 + trust_remote_code=renderer_config.trust_remote_code,
114 )
115 template_content = load_chat_template(chat_template=template)
116
@@ -143,7 +129,7 @@ def test_get_gen_prompt(
129 tokenizer=tokenizer,
130 conversation=mock_request.messages,
131 chat_template=mock_request.chat_template or template_content,
146 - model_config=model_config,
132 + renderer_config=renderer_config,
133 tools=None,
134 add_generation_prompt=mock_request.add_generation_prompt,
135 continue_final_message=mock_request.continue_final_message,
tests/entrypoints/openai/test_lora_resolvers.py
+15 -6
@@ -33,26 +33,34 @@ class MockModelConfig:
33 """Minimal mock ModelConfig for testing."""
34
35 model: str = MODEL_NAME
36 - tokenizer: str = MODEL_NAME
36 trust_remote_code: bool = False
38 - tokenizer_mode: str = "auto"
37 max_model_len: int = 100
40 - tokenizer_revision: str | None = None
38 multimodal_config: MultiModalConfig = field(default_factory=MultiModalConfig)
39 hf_config: MockHFConfig = field(default_factory=MockHFConfig)
40 logits_processors: list[str] | None = None
41 logits_processor_pattern: str | None = None
42 diff_sampling_param: dict | None = None
46 - allowed_local_media_path: str = ""
47 - allowed_media_domains: list[str] | None = None
43 encoder_config = None
44 generation_config: str = "auto"
50 - skip_tokenizer_init: bool = False
45
46 def get_diff_sampling_param(self):
47 return self.diff_sampling_param or {}
48
49
50 +@dataclass
51 +class MockRendererConfig:
52 + """Minimal mock RendererConfig for testing."""
53 +
54 + model_config: MockModelConfig
55 +
56 + tokenizer: str = MODEL_NAME
57 + tokenizer_mode: str = "auto"
58 + tokenizer_revision: str | None = None
59 + skip_tokenizer_init: bool = False
60 + allowed_local_media_path: str = ""
61 + allowed_media_domains: list[str] | None = None
62 +
63 +
64 class MockLoRAResolver(LoRAResolver):
65 async def resolve_lora(
66 self, base_model_name: str, lora_name: str
@@ -114,6 +122,7 @@ def mock_serving_setup():
122 mock_engine.add_lora.reset_mock()
123
124 mock_engine.model_config = MockModelConfig()
125 + mock_engine.renderer_config = MockRendererConfig(mock_engine.model_config)
126 mock_engine.input_processor = MagicMock()
127 mock_engine.io_processor = MagicMock()
128
tests/entrypoints/openai/test_serving_chat.py
+21 -7
@@ -346,27 +346,33 @@ class MockHFConfig:
346 class MockModelConfig:
347 task = "generate"
348 runner_type = "generate"
349 - tokenizer = MODEL_NAME
349 trust_remote_code = False
351 - tokenizer_mode = "auto"
350 max_model_len = 100
353 - tokenizer_revision = None
351 multimodal_config = MultiModalConfig()
352 hf_config = MockHFConfig()
353 logits_processors: list[str] | None = None
354 logits_processor_pattern = None
355 diff_sampling_param: dict | None = None
359 - allowed_local_media_path: str = ""
360 - allowed_media_domains: list[str] | None = None
356 encoder_config = None
357 generation_config: str = "auto"
363 - media_io_kwargs: dict[str, dict[str, Any]] = field(default_factory=dict)
364 - skip_tokenizer_init = False
358
359 def get_diff_sampling_param(self):
360 return self.diff_sampling_param or {}
361
362
363 +@dataclass
364 +class MockRendererConfig:
365 + model_config: MockModelConfig = field(default_factory=MockModelConfig)
366 +
367 + tokenizer = MODEL_NAME
368 + tokenizer_mode = "auto"
369 + tokenizer_revision = None
370 + skip_tokenizer_init = False
371 + media_io_kwargs: dict[str, dict[str, Any]] = field(default_factory=dict)
372 + allowed_local_media_path: str = ""
373 + allowed_media_domains: list[str] | None = None
374 +
375 +
376 def _build_serving_chat(engine: AsyncLLM) -> OpenAIServingChat:
377 models = OpenAIServingModels(
378 engine_client=engine,
@@ -399,6 +405,7 @@ def _build_serving_chat(engine: AsyncLLM) -> OpenAIServingChat:
405 @dataclass
406 class MockEngine:
407 model_config: MockModelConfig = field(default_factory=MockModelConfig)
408 + renderer_config: MockRendererConfig = field(default_factory=MockRendererConfig)
409 input_processor: MagicMock = field(default_factory=MagicMock)
410 io_processor: MagicMock = field(default_factory=MagicMock)
411
@@ -429,6 +436,7 @@ async def test_serving_chat_returns_correct_model_name():
436 mock_engine.get_tokenizer.return_value = get_tokenizer(MODEL_NAME)
437 mock_engine.errored = False
438 mock_engine.model_config = MockModelConfig()
439 + mock_engine.renderer_config = MockRendererConfig(mock_engine.model_config)
440 mock_engine.input_processor = MagicMock()
441 mock_engine.io_processor = MagicMock()
442
@@ -459,6 +467,7 @@ async def test_serving_chat_should_set_correct_max_tokens():
467 mock_engine.get_tokenizer.return_value = get_tokenizer(MODEL_NAME)
468 mock_engine.errored = False
469 mock_engine.model_config = MockModelConfig()
470 + mock_engine.renderer_config = MockRendererConfig(mock_engine.model_config)
471 mock_engine.input_processor = MagicMock()
472 mock_engine.io_processor = MagicMock()
473
@@ -492,6 +501,7 @@ async def test_serving_chat_should_set_correct_max_tokens():
501 mock_engine.get_tokenizer.return_value = get_tokenizer(MODEL_NAME)
502 mock_engine.errored = False
503 mock_engine.model_config = mock_model_config
504 + mock_engine.renderer_config = MockRendererConfig(mock_model_config)
505 mock_engine.input_processor = MagicMock()
506 mock_engine.io_processor = MagicMock()
507
@@ -537,6 +547,7 @@ async def test_serving_chat_should_set_correct_max_tokens():
547 mock_engine.get_tokenizer.return_value = get_tokenizer(MODEL_NAME)
548 mock_engine.errored = False
549 mock_engine.model_config = mock_model_config
550 + mock_engine.renderer_config = MockRendererConfig(mock_model_config)
551 mock_engine.input_processor = MagicMock()
552 mock_engine.io_processor = MagicMock()
553
@@ -583,6 +594,7 @@ async def test_serving_chat_could_load_correct_generation_config():
594 mock_engine.get_tokenizer.return_value = get_tokenizer(MODEL_NAME)
595 mock_engine.errored = False
596 mock_engine.model_config = mock_model_config
597 + mock_engine.renderer_config = MockRendererConfig(mock_model_config)
598 mock_engine.input_processor = MagicMock()
599 mock_engine.io_processor = MagicMock()
600
@@ -629,6 +641,7 @@ async def test_serving_chat_did_set_correct_cache_salt(model_type):
641 mock_engine.get_tokenizer.return_value = get_tokenizer(MODEL_NAME)
642 mock_engine.errored = False
643 mock_engine.model_config = mock_model_config
644 + mock_engine.renderer_config = MockRendererConfig(mock_model_config)
645 mock_engine.input_processor = MagicMock()
646 mock_engine.io_processor = MagicMock()
647
@@ -662,6 +675,7 @@ async def test_serving_chat_data_parallel_rank_extraction():
675 mock_engine.get_tokenizer.return_value = get_tokenizer(MODEL_NAME)
676 mock_engine.errored = False
677 mock_engine.model_config = MockModelConfig()
678 + mock_engine.renderer_config = MockRendererConfig(mock_engine.model_config)
679 mock_engine.input_processor = MagicMock()
680 mock_engine.io_processor = MagicMock()
681
tests/entrypoints/openai/test_serving_engine.py
+7 -1
@@ -7,7 +7,7 @@ from unittest.mock import Mock
7
8 import pytest
9
10 -from vllm.config import ModelConfig
10 +from vllm.config import ModelConfig, RendererConfig
11 from vllm.entrypoints.openai.serving_engine import OpenAIServing
12 from vllm.entrypoints.openai.serving_models import OpenAIServingModels
13 from vllm.tokenizers import MistralTokenizer
@@ -19,10 +19,16 @@ def serving() -> OpenAIServing:
19
20 # Create minimal mocks
21 engine_client = Mock()
22 +
23 model_config = Mock(spec=ModelConfig)
24 model_config.max_model_len = 32768
25 +
26 + renderer_config = Mock(spec=RendererConfig)
27 + renderer_config.model_config = model_config
28 +
29 models = Mock(spec=OpenAIServingModels)
30 models.model_config = model_config
31 + models.renderer_config = renderer_config
32 models.input_processor = Mock()
33 models.io_processor = Mock()
34
tests/entrypoints/openai/test_serving_models.py
+7 -1
@@ -6,7 +6,7 @@ from unittest.mock import MagicMock
6
7 import pytest
8
9 -from vllm.config import ModelConfig
9 +from vllm.config import ModelConfig, RendererConfig
10 from vllm.engine.protocol import EngineClient
11 from vllm.entrypoints.openai.protocol import (
12 ErrorResponse,
@@ -27,9 +27,15 @@ LORA_UNLOADING_SUCCESS_MESSAGE = (
27 async def _async_serving_models_init() -> OpenAIServingModels:
28 mock_engine_client = MagicMock(spec=EngineClient)
29 # Set the max_model_len attribute to avoid missing attribute
30 +
31 mock_model_config = MagicMock(spec=ModelConfig)
32 mock_model_config.max_model_len = 2048
33 +
34 + mock_renderer_config = MagicMock(spec=RendererConfig)
35 + mock_renderer_config.model_config = mock_model_config
36 +
37 mock_engine_client.model_config = mock_model_config
38 + mock_engine_client.renderer_config = mock_renderer_config
39 mock_engine_client.input_processor = MagicMock()
40 mock_engine_client.io_processor = MagicMock()
41
tests/entrypoints/test_chat_utils.py
+71 -123
@@ -12,7 +12,7 @@ from mistral_common.tokens.tokenizers.base import SpecialTokenPolicy
12 from vllm.assets.audio import AudioAsset
13 from vllm.assets.image import ImageAsset
14 from vllm.assets.video import VideoAsset
15 -from vllm.config import ModelConfig
15 +from vllm.config import ModelConfig, RendererConfig
16 from vllm.entrypoints.chat_utils import (
17 _try_extract_ast,
18 apply_mistral_chat_template,
@@ -233,7 +233,7 @@ def test_parse_chat_messages_single_image(
233 ],
234 }
235 ],
236 - phi3v_model_config,
236 + RendererConfig(model_config=phi3v_model_config),
237 content_format="string",
238 )
239
@@ -265,7 +265,7 @@ def test_parse_chat_messages_single_image_with_uuid(
265 ],
266 }
267 ],
268 - phi3v_model_config,
268 + RendererConfig(model_config=phi3v_model_config),
269 content_format="string",
270 )
271
@@ -295,7 +295,7 @@ def test_parse_chat_messages_single_empty_image_with_uuid(
295 ],
296 }
297 ],
298 - phi3v_model_config,
298 + RendererConfig(model_config=phi3v_model_config),
299 content_format="string",
300 )
301
@@ -328,7 +328,7 @@ def test_parse_chat_messages_single_image_with_bad_uuid_format(
328 ],
329 }
330 ],
331 - phi3v_model_config,
331 + RendererConfig(model_config=phi3v_model_config),
332 content_format="string",
333 )
334
@@ -369,7 +369,7 @@ def test_parse_chat_messages_multiple_images_with_uuids(
369 ],
370 }
371 ],
372 - phi3v_model_config,
372 + RendererConfig(model_config=phi3v_model_config),
373 content_format="string",
374 )
375
@@ -409,7 +409,7 @@ def test_parse_chat_messages_multiple_empty_images_with_uuids(
409 ],
410 }
411 ],
412 - phi3v_model_config,
412 + RendererConfig(model_config=phi3v_model_config),
413 content_format="string",
414 )
415
@@ -451,7 +451,7 @@ def test_parse_chat_messages_mixed_empty_images_with_uuids(
451 ],
452 }
453 ],
454 - phi3v_model_config,
454 + RendererConfig(model_config=phi3v_model_config),
455 content_format="string",
456 )
457
@@ -485,7 +485,7 @@ async def test_parse_chat_messages_single_image_with_uuid_async(
485 ],
486 }
487 ],
488 - phi3v_model_config,
488 + RendererConfig(model_config=phi3v_model_config),
489 content_format="string",
490 )
491
@@ -516,7 +516,7 @@ async def test_parse_chat_messages_empty_image_with_uuid_async(
516 ],
517 }
518 ],
519 - phi3v_model_config,
519 + RendererConfig(model_config=phi3v_model_config),
520 content_format="string",
521 )
522
@@ -554,7 +554,7 @@ async def test_parse_chat_messages_multiple_images_with_uuids_async(
554 ],
555 }
556 ],
557 - phi3v_model_config,
557 + RendererConfig(model_config=phi3v_model_config),
558 content_format="string",
559 )
560
@@ -595,7 +595,7 @@ async def test_parse_chat_messages_multiple_empty_images_with_uuids_async(
595 ],
596 }
597 ],
598 - phi3v_model_config,
598 + RendererConfig(model_config=phi3v_model_config),
599 content_format="string",
600 )
601
@@ -634,7 +634,7 @@ async def test_parse_chat_messages_multiple_images_with_partial_uuids_async(
634 ],
635 }
636 ],
637 - phi3v_model_config,
637 + RendererConfig(model_config=phi3v_model_config),
638 content_format="string",
639 )
640
@@ -660,7 +660,7 @@ def test_parse_chat_messages_empty_system(
660 "content": [{"type": "text", "text": "Who are you?"}],
661 },
662 ],
663 - mistral_model_config,
663 + RendererConfig(model_config=mistral_model_config),
664 content_format="string",
665 )
666 assert conversation == [
@@ -677,7 +677,7 @@ def test_parse_chat_messages_empty_system(
677 "content": [{"type": "text", "text": "Who are you?"}],
678 },
679 ],
680 - mistral_model_config,
680 + RendererConfig(model_config=mistral_model_config),
681 content_format="openai",
682 )
683 assert conversation == [
@@ -701,7 +701,7 @@ async def test_parse_chat_messages_single_image_async(
701 ],
702 }
703 ],
704 - phi3v_model_config,
704 + RendererConfig(model_config=phi3v_model_config),
705 content_format="string",
706 )
707
@@ -730,7 +730,7 @@ def test_parse_chat_messages_multiple_images(
730 ],
731 }
732 ],
733 - phi3v_model_config,
733 + RendererConfig(model_config=phi3v_model_config),
734 content_format="string",
735 )
736
@@ -758,7 +758,7 @@ def test_parse_chat_messages_empty_pil_image_with_uuid(
758 ],
759 }
760 ],
761 - phi3v_model_config,
761 + RendererConfig(model_config=phi3v_model_config),
762 content_format="string",
763 )
764
@@ -786,7 +786,7 @@ def test_parse_chat_messages_empty_image_embeds_with_uuid(
786 ],
787 }
788 ],
789 - phi3v_model_config_image_embeds,
789 + RendererConfig(model_config=phi3v_model_config_image_embeds),
790 content_format="string",
791 )
792
@@ -818,7 +818,7 @@ def test_parse_chat_messages_empty_audio_embeds_with_uuid(
818 ],
819 }
820 ],
821 - audio_embeds_model_config,
821 + RendererConfig(model_config=audio_embeds_model_config),
822 content_format="string",
823 )
824
@@ -858,7 +858,7 @@ def test_parse_chat_messages_audio_embeds_with_string(
858 ],
859 }
860 ],
861 - audio_embeds_model_config,
861 + RendererConfig(model_config=audio_embeds_model_config),
862 content_format="string",
863 )
864
@@ -900,7 +900,7 @@ async def test_parse_chat_messages_audio_embeds_async(
900 ],
901 }
902 ],
903 - audio_embeds_model_config,
903 + RendererConfig(model_config=audio_embeds_model_config),
904 content_format="string",
905 )
906
@@ -1108,7 +1108,7 @@ async def test_parse_chat_messages_empty_image_embeds_with_uuid_async(
1108 ],
1109 }
1110 ],
1111 - phi3v_model_config_image_embeds,
1111 + RendererConfig(model_config=phi3v_model_config_image_embeds),
1112 content_format="string",
1113 )
1114
@@ -1144,7 +1144,7 @@ async def test_parse_chat_messages_multiple_images_async(
1144 ],
1145 }
1146 ],
1147 - phi3v_model_config,
1147 + RendererConfig(model_config=phi3v_model_config),
1148 content_format="string",
1149 )
1150
@@ -1176,7 +1176,7 @@ def test_parse_chat_messages_placeholder_already_in_prompt(
1176 ],
1177 }
1178 ],
1179 - phi3v_model_config,
1179 + RendererConfig(model_config=phi3v_model_config),
1180 content_format="string",
1181 )
1182 assert conversation == [
@@ -1208,7 +1208,7 @@ def test_parse_chat_messages_placeholder_one_already_in_prompt(
1208 ],
1209 }
1210 ],
1211 - phi3v_model_config,
1211 + RendererConfig(model_config=phi3v_model_config),
1212 content_format="string",
1213 )
1214
@@ -1245,7 +1245,7 @@ def test_parse_chat_messages_multiple_images_across_messages(
1245 ],
1246 },
1247 ],
1248 - phi3v_model_config,
1248 + RendererConfig(model_config=phi3v_model_config),
1249 content_format="string",
1250 )
1251
@@ -1289,7 +1289,7 @@ def test_parse_chat_messages_multiple_images_with_uuids_across_messages(
1289 ],
1290 },
1291 ],
1292 - phi3v_model_config,
1292 + RendererConfig(model_config=phi3v_model_config),
1293 content_format="string",
1294 )
1295
@@ -1314,7 +1314,7 @@ def test_parse_chat_messages_context_text_format(
1314 {"role": "assistant", "content": "Some stuff."},
1315 {"role": "user", "content": "What about this one?"},
1316 ],
1317 - phi3v_model_config,
1317 + RendererConfig(model_config=phi3v_model_config),
1318 content_format="openai",
1319 )
1320
@@ -1367,7 +1367,7 @@ def test_parse_chat_messages_rejects_too_many_images_in_one_message(
1367 ],
1368 }
1369 ],
1370 - phi3v_model_config,
1370 + RendererConfig(model_config=phi3v_model_config),
1371 content_format="string",
1372 )
1373
@@ -1410,7 +1410,7 @@ def test_parse_chat_messages_rejects_too_many_images_across_messages(
1410 ],
1411 },
1412 ],
1413 - phi3v_model_config,
1413 + RendererConfig(model_config=phi3v_model_config),
1414 content_format="string",
1415 )
1416
@@ -1430,7 +1430,7 @@ def test_parse_chat_messages_multiple_images_uncommon_input(
1430 ],
1431 }
1432 ],
1433 - phi3v_model_config,
1433 + RendererConfig(model_config=phi3v_model_config),
1434 content_format="string",
1435 )
1436
@@ -1464,7 +1464,7 @@ def test_parse_chat_messages_multiple_images_interleave(
1464 ],
1465 }
1466 ],
1467 - phi3v_model_config_mm_interleaved,
1467 + RendererConfig(model_config=phi3v_model_config_mm_interleaved),
1468 content_format="string",
1469 )
1470
@@ -1500,7 +1500,7 @@ async def test_parse_chat_messages_multiple_images_interleave_async(
1500 ],
1501 }
1502 ],
1503 - phi3v_model_config_mm_interleaved,
1503 + RendererConfig(model_config=phi3v_model_config_mm_interleaved),
1504 content_format="string",
1505 )
1506
@@ -1545,7 +1545,7 @@ async def test_parse_chat_messages_multiple_images_with_uuids_interleave_async(
1545 ],
1546 }
1547 ],
1548 - phi3v_model_config_mm_interleaved,
1548 + RendererConfig(model_config=phi3v_model_config_mm_interleaved),
1549 content_format="string",
1550 )
1551
@@ -1583,7 +1583,7 @@ def test_parse_chat_messages_multiple_images_multiple_messages_interleave(
1583 ],
1584 },
1585 ],
1586 - phi3v_model_config_mm_interleaved,
1586 + RendererConfig(model_config=phi3v_model_config_mm_interleaved),
1587 content_format="string",
1588 )
1589
@@ -1631,7 +1631,7 @@ def test_parse_chat_messages_multiple_images_with_uuids_multiple_messages_interl
1631 ],
1632 },
1633 ],
1634 - phi3v_model_config_mm_interleaved,
1634 + RendererConfig(model_config=phi3v_model_config_mm_interleaved),
1635 content_format="string",
1636 )
1637
@@ -1675,7 +1675,7 @@ def test_parse_chat_messages_multiple_modals_multiple_messages_interleave(
1675 ],
1676 },
1677 ],
1678 - qwen25omni_model_config_mm_interleaved,
1678 + RendererConfig(model_config=qwen25omni_model_config_mm_interleaved),
1679 content_format="string",
1680 )
1681
@@ -1743,7 +1743,7 @@ def test_parse_chat_messages_multiple_modals_with_uuids_multiple_messages_interl
1743 ],
1744 },
1745 ],
1746 - qwen25omni_model_config_mm_interleaved,
1746 + RendererConfig(model_config=qwen25omni_model_config_mm_interleaved),
1747 content_format="string",
1748 )
1749
@@ -1813,7 +1813,7 @@ def test_parse_chat_messages_multiple_modals_with_uuids_multiple_empty_media_mes
1813 ],
1814 },
1815 ],
1816 - qwen25omni_model_config_mm_interleaved,
1816 + RendererConfig(model_config=qwen25omni_model_config_mm_interleaved),
1817 content_format="string",
1818 )
1819
@@ -1879,7 +1879,7 @@ def test_parse_chat_messages_multiple_modals_with_partial_uuids_multiple_message
1879 ],
1880 },
1881 ],
1882 - qwen25omni_model_config_mm_interleaved,
1882 + RendererConfig(model_config=qwen25omni_model_config_mm_interleaved),
1883 content_format="string",
1884 )
1885
@@ -1927,7 +1927,7 @@ def test_parse_chat_messages_multiple_images_interleave_with_placeholders(
1927 ],
1928 }
1929 ],
1930 - phi3v_model_config_mm_interleaved,
1930 + RendererConfig(model_config=phi3v_model_config_mm_interleaved),
1931 content_format="string",
1932 )
1933
@@ -1945,24 +1945,11 @@ def test_resolve_hf_chat_template(sample_json_schema, model, use_tools):
1945 model_info = HF_EXAMPLE_MODELS.find_hf_info(model)
1946 model_info.check_available_online(on_fail="skip")
1947
1948 - model_config = ModelConfig(
1949 - model,
1950 - tokenizer=model_info.tokenizer or model,
1951 - tokenizer_mode=model_info.tokenizer_mode,
1952 - revision=model_info.revision,
1953 - trust_remote_code=model_info.trust_remote_code,
1954 - hf_overrides=model_info.hf_overrides,
1955 - skip_tokenizer_init=model_info.require_embed_inputs,
1956 - enable_prompt_embeds=model_info.require_embed_inputs,
1957 - enable_mm_embeds=model_info.require_embed_inputs,
1958 - enforce_eager=model_info.enforce_eager,
1959 - dtype=model_info.dtype,
1960 - )
1961 -
1962 - # Build the tokenizer
1948 + renderer_config = model_info.build_renderer_config(model)
1949 +
1950 tokenizer = get_tokenizer(
1964 - model,
1965 - trust_remote_code=model_config.trust_remote_code,
1951 + renderer_config.tokenizer,
1952 + trust_remote_code=renderer_config.trust_remote_code,
1953 )
1954
1955 tools = (
@@ -1985,7 +1972,7 @@ def test_resolve_hf_chat_template(sample_json_schema, model, use_tools):
1972 tokenizer,
1973 chat_template=None,
1974 tools=tools,
1988 - model_config=model_config,
1975 + model_config=renderer_config.model_config,
1976 )
1977 assert isinstance(chat_template, str)
1978
@@ -2047,24 +2034,11 @@ def test_resolve_hf_chat_template_kwargs(sample_json_schema, model, expected_kwa
2034 "enable_thinking": True,
2035 }
2036
2050 - model_config = ModelConfig(
2051 - model,
2052 - tokenizer=model_info.tokenizer or model,
2053 - tokenizer_mode=model_info.tokenizer_mode,
2054 - revision=model_info.revision,
2055 - trust_remote_code=model_info.trust_remote_code,
2056 - hf_overrides=model_info.hf_overrides,
2057 - skip_tokenizer_init=model_info.require_embed_inputs,
2058 - enable_prompt_embeds=model_info.require_embed_inputs,
2059 - enable_mm_embeds=model_info.require_embed_inputs,
2060 - enforce_eager=model_info.enforce_eager,
2061 - dtype=model_info.dtype,
2062 - )
2063 -
2064 - # Build the tokenizer
2037 + renderer_config = model_info.build_renderer_config(model)
2038 +
2039 tokenizer = get_tokenizer(
2066 - model,
2067 - trust_remote_code=model_config.trust_remote_code,
2040 + renderer_config.tokenizer,
2041 + trust_remote_code=renderer_config.trust_remote_code,
2042 )
2043
2044 # Test detecting the tokenizer's chat_template
@@ -2072,7 +2046,7 @@ def test_resolve_hf_chat_template_kwargs(sample_json_schema, model, expected_kwa
2046 tokenizer,
2047 chat_template=None,
2048 tools=tools,
2075 - model_config=model_config,
2049 + model_config=renderer_config.model_config,
2050 )
2051 with pytest.raises(
2052 ValueError, match="Found unexpected chat template kwargs from request"
@@ -2143,23 +2117,11 @@ def test_resolve_content_format_hf_defined(model, expected_format):
2117 model_info = HF_EXAMPLE_MODELS.find_hf_info(model)
2118 model_info.check_available_online(on_fail="skip")
2119
2146 - model_config = ModelConfig(
2147 - model,
2148 - tokenizer=model_info.tokenizer or model,
2149 - tokenizer_mode=model_info.tokenizer_mode,
2150 - revision=model_info.revision,
2151 - trust_remote_code=model_info.trust_remote_code,
2152 - hf_overrides=model_info.hf_overrides,
2153 - skip_tokenizer_init=model_info.require_embed_inputs,
2154 - enable_prompt_embeds=model_info.require_embed_inputs,
2155 - enable_mm_embeds=model_info.require_embed_inputs,
2156 - enforce_eager=model_info.enforce_eager,
2157 - dtype=model_info.dtype,
2158 - )
2120 + renderer_config = model_info.build_renderer_config(model)
2121
2122 tokenizer = get_tokenizer(
2161 - model,
2162 - trust_remote_code=model_config.trust_remote_code,
2123 + renderer_config.tokenizer,
2124 + trust_remote_code=renderer_config.trust_remote_code,
2125 )
2126
2127 # Test detecting the tokenizer's chat_template
@@ -2167,7 +2129,7 @@ def test_resolve_content_format_hf_defined(model, expected_format):
2129 tokenizer,
2130 chat_template=None,
2131 tools=None,
2170 - model_config=model_config,
2132 + model_config=renderer_config.model_config,
2133 )
2134 assert isinstance(chat_template, str)
2135
@@ -2181,7 +2143,7 @@ def test_resolve_content_format_hf_defined(model, expected_format):
2143 None,
2144 "auto",
2145 tokenizer,
2184 - model_config=model_config,
2146 + renderer_config=renderer_config,
2147 )
2148
2149 assert resolved_format == expected_format
@@ -2203,23 +2165,11 @@ def test_resolve_content_format_fallbacks(model, expected_format):
2165 model_info = HF_EXAMPLE_MODELS.find_hf_info(model)
2166 model_info.check_available_online(on_fail="skip")
2167
2206 - model_config = ModelConfig(
2207 - model,
2208 - tokenizer=model_info.tokenizer or model,
2209 - tokenizer_mode=model_info.tokenizer_mode,
2210 - revision=model_info.revision,
2211 - trust_remote_code=model_info.trust_remote_code,
2212 - hf_overrides=model_info.hf_overrides,
2213 - skip_tokenizer_init=model_info.require_embed_inputs,
2214 - enable_prompt_embeds=model_info.require_embed_inputs,
2215 - enable_mm_embeds=model_info.require_embed_inputs,
2216 - enforce_eager=model_info.enforce_eager,
2217 - dtype=model_info.dtype,
2218 - )
2168 + renderer_config = model_info.build_renderer_config(model)
2169
2170 tokenizer = get_tokenizer(
2221 - model_config.tokenizer,
2222 - trust_remote_code=model_config.trust_remote_code,
2171 + renderer_config.tokenizer,
2172 + trust_remote_code=renderer_config.trust_remote_code,
2173 )
2174
2175 # Test detecting the tokenizer's chat_template
@@ -2227,7 +2177,7 @@ def test_resolve_content_format_fallbacks(model, expected_format):
2177 tokenizer,
2178 chat_template=None,
2179 tools=None,
2230 - model_config=model_config,
2180 + model_config=renderer_config.model_config,
2181 )
2182 assert isinstance(chat_template, str)
2183
@@ -2241,7 +2191,7 @@ def test_resolve_content_format_fallbacks(model, expected_format):
2191 None,
2192 "auto",
2193 tokenizer,
2244 - model_config=model_config,
2194 + renderer_config=renderer_config,
2195 )
2196
2197 assert resolved_format == expected_format
@@ -2272,15 +2222,13 @@ def test_resolve_content_format_fallbacks(model, expected_format):
2222 ],
2223 )
2224 def test_resolve_content_format_examples(template_path, expected_format):
2275 - model_config = ModelConfig(
2276 - PHI3V_MODEL_ID, # Dummy
2277 - tokenizer=PHI3V_MODEL_ID, # Dummy
2278 - trust_remote_code=True,
2279 - )
2225 + model = PHI3V_MODEL_ID # Dummy
2226 + model_config = ModelConfig(model, trust_remote_code=True)
2227 + renderer_config = RendererConfig(model_config=model_config, tokenizer=model)
2228
2229 dummy_tokenizer = get_tokenizer(
2282 - PHI3V_MODEL_ID, # Dummy
2283 - trust_remote_code=model_config.trust_remote_code,
2230 + renderer_config.tokenizer,
2231 + trust_remote_code=renderer_config.trust_remote_code,
2232 )
2233 dummy_tokenizer.chat_template = None
2234
@@ -2297,7 +2245,7 @@ def test_resolve_content_format_examples(template_path, expected_format):
2245 None,
2246 "auto",
2247 dummy_tokenizer,
2300 - model_config=model_config,
2248 + renderer_config=renderer_config,
2249 )
2250
2251 assert resolved_format == expected_format
@@ -2332,7 +2280,7 @@ def test_parse_chat_messages_include_thinking_chunk(mistral_model_config):
2280
2281 conversation_with_thinking, _, _ = parse_chat_messages(
2282 messages,
2335 - mistral_model_config,
2283 + RendererConfig(model_config=mistral_model_config),
2284 content_format="openai",
2285 )
2286
@@ -2432,7 +2380,7 @@ def test_parse_chat_messages_single_empty_audio_with_uuid(
2380 ],
2381 }
2382 ],
2435 - qwen2_audio_model_config,
2383 + RendererConfig(model_config=qwen2_audio_model_config),
2384 content_format="string",
2385 )
2386
@@ -2466,7 +2414,7 @@ async def test_parse_chat_messages_single_empty_audio_with_uuid_async(
2414 ],
2415 }
2416 ],
2469 - qwen2_audio_model_config,
2417 + RendererConfig(model_config=qwen2_audio_model_config),
2418 content_format="string",
2419 )
2420
tests/lora/test_lora_manager.py
+11 -3
@@ -8,7 +8,7 @@ import torch
8 from safetensors.torch import load_file
9 from torch import nn
10
11 -from vllm.config import ModelConfig, VllmConfig
11 +from vllm.config import ModelConfig, RendererConfig, VllmConfig
12 from vllm.config.lora import LoRAConfig
13 from vllm.lora.layers import (
14 ColumnParallelLinearWithLoRA,
@@ -422,7 +422,11 @@ def test_lru_cache_worker_adapter_manager(dist_init, dummy_model, device, tmp_pa
422 )
423
424 model_config = ModelConfig(max_model_len=16)
425 - vllm_config = VllmConfig(model_config=model_config, lora_config=lora_config)
425 + vllm_config = VllmConfig(
426 + model_config=model_config,
427 + renderer_config=RendererConfig(model_config=model_config),
428 + lora_config=lora_config,
429 + )
430
431 vllm_config.scheduler_config.max_num_seqs = 4
432 vllm_config.scheduler_config.max_num_batched_tokens = 2
@@ -525,7 +529,11 @@ def test_worker_adapter_manager(dist_init, dummy_model_gate_up, device, tmp_path
529 )
530
531 model_config = ModelConfig(max_model_len=16)
528 - vllm_config = VllmConfig(model_config=model_config, lora_config=lora_config)
532 + vllm_config = VllmConfig(
533 + model_config=model_config,
534 + renderer_config=RendererConfig(model_config=model_config),
535 + lora_config=lora_config,
536 + )
537
538 vllm_config.scheduler_config.max_num_seqs = 4
539 vllm_config.scheduler_config.max_num_batched_tokens = 2
tests/lora/test_worker.py
+2
@@ -11,6 +11,7 @@ from vllm.config import (
11 DeviceConfig,
12 ModelConfig,
13 ParallelConfig,
14 + RendererConfig,
15 SchedulerConfig,
16 VllmConfig,
17 )
@@ -43,6 +44,7 @@ def test_worker_apply_lora(qwen3_lora_files):
44
45 vllm_config = VllmConfig(
46 model_config=model_config,
47 + renderer_config=RendererConfig(model_config=model_config),
48 load_config=LoadConfig(
49 download_dir=None,
50 load_format="dummy",
tests/model_executor/test_model_load_with_params.py
+13 -9
@@ -42,8 +42,10 @@ def test_model_loading_with_params(vllm_runner, monkeypatch):
42 "Write a short story about a robot that dreams for the first time.\n"
43 )
44
45 - model_config = vllm_model.llm.llm_engine.model_config
46 - model_tokenizer = vllm_model.llm.llm_engine.tokenizer
45 + llm_engine = vllm_model.llm.llm_engine
46 + model_config = llm_engine.model_config
47 + renderer_config = llm_engine.renderer_config
48 + tokenizer = llm_engine.tokenizer
49
50 # asserts on the bert model config file
51 assert model_config.encoder_config["max_seq_length"] == 512
@@ -54,8 +56,8 @@ def test_model_loading_with_params(vllm_runner, monkeypatch):
56 assert model_config.pooler_config.normalize
57
58 # asserts on the tokenizer loaded
57 - assert model_config.tokenizer == "BAAI/bge-base-en-v1.5"
58 - assert model_tokenizer.model_max_length == 512
59 + assert renderer_config.tokenizer == "BAAI/bge-base-en-v1.5"
60 + assert tokenizer.model_max_length == 512
61
62 def check_model(model):
63 assert isinstance(model, BertEmbeddingModel)
@@ -86,8 +88,10 @@ def test_roberta_model_loading_with_params(vllm_runner, monkeypatch):
88 "Write a short story about a robot that dreams for the first time.\n"
89 )
90
89 - model_config = vllm_model.llm.llm_engine.model_config
90 - model_tokenizer = vllm_model.llm.llm_engine.tokenizer
91 + llm_engine = vllm_model.llm.llm_engine
92 + model_config = llm_engine.model_config
93 + renderer_config = llm_engine.renderer_config
94 + tokenizer = llm_engine.tokenizer
95
96 # asserts on the bert model config file
97 assert model_config.encoder_config["max_seq_length"] == 512
@@ -98,8 +102,8 @@ def test_roberta_model_loading_with_params(vllm_runner, monkeypatch):
102 assert model_config.pooler_config.normalize
103
104 # asserts on the tokenizer loaded
101 - assert model_config.tokenizer == "intfloat/multilingual-e5-base"
102 - assert model_tokenizer.model_max_length == 512
105 + assert renderer_config.tokenizer == "intfloat/multilingual-e5-base"
106 + assert tokenizer.model_max_length == 512
107
108 def check_model(model):
109 assert isinstance(model, RobertaEmbeddingModel)
@@ -128,7 +132,7 @@ def test_facebook_roberta_model_loading_with_params(vllm_runner, monkeypatch):
132 "Write a short story about a robot that dreams for the first time.\n"
133 )
134
131 - assert vllm_model.llm.llm_engine.model_config.tokenizer == model_name
135 + assert vllm_model.llm.llm_engine.renderer_config.tokenizer == model_name
136
137 def check_model(model):
138 assert isinstance(model, RobertaEmbeddingModel)
tests/models/language/pooling/test_gritlm.py
+3 -2
@@ -6,7 +6,7 @@ import pytest
6 from scipy.spatial.distance import cosine
7
8 from vllm import LLM, SamplingParams
9 -from vllm.config import ModelConfig
9 +from vllm.config import ModelConfig, RendererConfig
10
11 from ....utils import RemoteOpenAIServer
12
@@ -31,7 +31,8 @@ def test_find_array():
31 dtype="bfloat16",
32 seed=0,
33 )
34 - pooling = GritLMMeanPool(model_config=model_config)
34 + renderer_config = RendererConfig(model_config=model_config)
35 + pooling = GritLMMeanPool(renderer_config=renderer_config)
36
37 arr = _arr([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
38
tests/models/multimodal/processing/test_common.py
+5 -17
@@ -25,7 +25,6 @@ from vllm.multimodal.processing import BaseMultiModalProcessor, InputProcessingC
25 from vllm.tokenizers import (
26 MistralTokenizer,
27 TokenizerLike,
28 - cached_tokenizer_from_config,
28 )
29
30 from ....multimodal.utils import random_audio, random_image, random_video
@@ -212,31 +211,20 @@ def _test_processing_correctness(
211 else:
212 model_info = HF_EXAMPLE_MODELS.find_hf_info(model_id_or_arch)
213 model_id = model_id_or_arch
214 +
215 model_info.check_available_online(on_fail="skip")
216 model_info.check_transformers_version(on_fail="skip")
217
218 - model_config = ModelConfig(
219 - model_id,
220 - tokenizer=model_info.tokenizer or model_id,
221 - tokenizer_mode=model_info.tokenizer_mode,
222 - revision=model_info.revision,
223 - trust_remote_code=model_info.trust_remote_code,
224 - hf_overrides=model_info.hf_overrides,
218 + renderer_config = model_info.build_renderer_config(
219 + model=model_id,
220 # Ensure that the cache can fit all of the data
221 mm_processor_cache_gb=2048,
227 - skip_tokenizer_init=model_info.require_embed_inputs,
228 - enable_prompt_embeds=model_info.require_embed_inputs,
229 - enable_mm_embeds=model_info.require_embed_inputs,
230 - enforce_eager=model_info.enforce_eager,
231 - dtype=model_info.dtype,
222 )
223 + model_config = renderer_config.model_config
224
225 model_cls = MULTIMODAL_REGISTRY._get_model_cls(model_config)
226 factories = model_cls._processor_factory
236 - ctx = InputProcessingContext(
237 - model_config,
238 - tokenizer=cached_tokenizer_from_config(model_config),
239 - )
227 + ctx = InputProcessingContext.from_config(renderer_config)
228 cache = MultiModalProcessorOnlyCache(model_config)
229
230 processing_info = factories.info(ctx)
tests/models/multimodal/processing/test_glm4_1v.py
+2 -2
@@ -40,7 +40,7 @@ def test_processor_override(
40 mm_processor_kwargs=None,
41 limit_mm_per_prompt={"video": 1},
42 )
43 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
43 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
44 tokenizer = processor.info.get_tokenizer()
45 hf_processor_mm_kwargs = {"fps": fps}
46
@@ -79,7 +79,7 @@ def test_video_loader_consistency(
79 mm_processor_kwargs=None,
80 limit_mm_per_prompt={"video": 1},
81 )
82 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
82 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
83 hf_processor_mm_kwargs = {"fps": fps}
84
85 # Build the image str / prompt based on the number of images we pass
tests/models/multimodal/processing/test_h2ovl.py
+1 -1
@@ -162,7 +162,7 @@ def test_processor_override(
162 mm_processor_kwargs=mm_processor_kwargs if kwargs_on_init else None,
163 limit_mm_per_prompt={"image": len(size_factors)},
164 )
165 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
165 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
166 hf_processor_mm_kwargs = {} if kwargs_on_init else mm_processor_kwargs
167
168 min_num = min_dynamic_patch if dynamic_image_size else 1
tests/models/multimodal/processing/test_idefics3.py
+1 -1
@@ -38,7 +38,7 @@ def test_processor_override(
38 mm_processor_kwargs=mm_processor_kwargs if kwargs_on_init else None,
39 limit_mm_per_prompt={"image": num_imgs},
40 )
41 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
41 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
42 hf_processor_mm_kwargs = {} if kwargs_on_init else mm_processor_kwargs
43
44 # Build the image str / prompt based on the number of images we pass
tests/models/multimodal/processing/test_internvl.py
+1 -1
@@ -116,7 +116,7 @@ def test_processor_override(
116 mm_processor_kwargs=mm_processor_kwargs if kwargs_on_init else None,
117 limit_mm_per_prompt={"image": len(size_factors)},
118 )
119 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
119 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
120 hf_processor_mm_kwargs = {} if kwargs_on_init else mm_processor_kwargs
121
122 min_num = min_dynamic_patch if dynamic_image_size else 1
tests/models/multimodal/processing/test_llama4.py
+1 -1
@@ -30,7 +30,7 @@ def test_processor_override(
30 limit_mm_per_prompt={"image": num_imgs},
31 mm_processor_cache_gb=mm_processor_cache_gb,
32 )
33 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
33 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
34 config = processor.info.get_hf_config()
35 tokenizer = processor.info.get_tokenizer()
36 hf_processor = processor.info.get_hf_processor()
tests/models/multimodal/processing/test_llava_next.py
+3 -3
@@ -42,7 +42,7 @@ def test_processor_max_tokens(model_id):
42 mm_processor_kwargs=None,
43 limit_mm_per_prompt={"image": 1},
44 )
45 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
45 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
46 info = processor.info
47
48 seen_aspect_ratios = set[float]()
@@ -140,7 +140,7 @@ def test_processor_prompt_replacements_regression(model_id, num_imgs):
140 mm_processor_kwargs=None,
141 limit_mm_per_prompt={"image": num_imgs},
142 )
143 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
143 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
144
145 image_ratios = [
146 (171, 152),
@@ -173,7 +173,7 @@ def test_processor_prompt_replacements_all(model_id, num_imgs):
173 mm_processor_kwargs=None,
174 limit_mm_per_prompt={"image": num_imgs},
175 )
176 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
176 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
177
178 seen_aspect_ratios = set[float]()
179 image_sizes = list[ImageSize]()
tests/models/multimodal/processing/test_llava_onevision.py
+3 -3
@@ -42,7 +42,7 @@ def test_processor_max_tokens(model_id):
42 mm_processor_kwargs=None,
43 limit_mm_per_prompt={"image": 1},
44 )
45 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
45 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
46 info = processor.info
47
48 seen_aspect_ratios = set[float]()
@@ -138,7 +138,7 @@ def test_processor_prompt_replacements_regression(model_id, num_imgs):
138 mm_processor_kwargs=None,
139 limit_mm_per_prompt={"image": num_imgs},
140 )
141 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
141 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
142
143 image_ratios = [
144 (171, 152),
@@ -171,7 +171,7 @@ def test_processor_prompt_replacements_all(model_id, num_imgs):
171 mm_processor_kwargs=None,
172 limit_mm_per_prompt={"image": num_imgs},
173 )
174 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
174 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
175
176 seen_aspect_ratios = set[float]()
177 image_sizes = list[ImageSize]()
tests/models/multimodal/processing/test_minimax_vl_01.py
+2 -2
@@ -24,7 +24,7 @@ def test_processor_override(
24 mm_processor_kwargs=None,
25 limit_mm_per_prompt={"image": num_imgs},
26 )
27 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
27 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
28 prompt = "<image>" * num_imgs
29 image = Image.new("RGB", size=(364, 364))
30 mm_data = {"image": [image] * num_imgs}
@@ -83,7 +83,7 @@ def test_processor_prompt_replacements_regression(model_id, num_imgs):
83 mm_processor_kwargs=None,
84 limit_mm_per_prompt={"image": num_imgs},
85 )
86 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
86 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
87
88 image_ratios = [
89 (171, 152),
tests/models/multimodal/processing/test_mllama4.py
+1 -1
@@ -25,7 +25,7 @@ def test_profiling(model_id: str, max_model_len: int):
25 limit_mm_per_prompt=mm_counts,
26 )
27
28 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
28 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
29 profiler = MultiModalProfiler(processor)
30
31 decoder_dummy_data = profiler.get_decoder_dummy_data(
tests/models/multimodal/processing/test_nemotron_vl.py
+1 -1
@@ -118,7 +118,7 @@ def test_processor_override(
118 mm_processor_kwargs=mm_processor_kwargs if kwargs_on_init else None,
119 limit_mm_per_prompt={"image": len(size_factors)},
120 )
121 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
121 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
122 hf_processor_mm_kwargs = {} if kwargs_on_init else mm_processor_kwargs
123
124 min_num = min_dynamic_patch if dynamic_image_size else 1
tests/models/multimodal/processing/test_phi3v.py
+1 -1
@@ -39,7 +39,7 @@ def test_processor_override(
39 mm_processor_kwargs=mm_processor_kwargs if kwargs_on_init else None,
40 limit_mm_per_prompt={"image": num_imgs},
41 )
42 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
42 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
43 hf_processor_mm_kwargs = {} if kwargs_on_init else mm_processor_kwargs
44
45 # Build the image str / prompt based on the number of images we pass
tests/models/multimodal/processing/test_phi4mm.py
+1 -1
@@ -39,7 +39,7 @@ def test_processor_override(
39 mm_processor_kwargs=mm_processor_kwargs if kwargs_on_init else None,
40 limit_mm_per_prompt={"image": num_imgs},
41 )
42 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
42 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
43 hf_processor_mm_kwargs = {} if kwargs_on_init else mm_processor_kwargs
44
45 # Build the image str / prompt based on the number of images we pass
tests/models/multimodal/processing/test_qwen2_vl.py
+1 -1
@@ -34,7 +34,7 @@ def test_processor_override(
34 mm_processor_kwargs=mm_processor_kwargs if kwargs_on_init else None,
35 limit_mm_per_prompt={"image": num_imgs},
36 )
37 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
37 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
38 tokenizer = processor.info.get_tokenizer()
39 hf_processor_mm_kwargs = {} if kwargs_on_init else mm_processor_kwargs
40
tests/models/multimodal/processing/test_smolvlm.py
+1 -1
@@ -38,7 +38,7 @@ def test_processor_override(
38 mm_processor_kwargs=mm_processor_kwargs if kwargs_on_init else None,
39 limit_mm_per_prompt={"image": num_imgs},
40 )
41 - processor = MULTIMODAL_REGISTRY.create_processor(ctx.model_config)
41 + processor = MULTIMODAL_REGISTRY.create_processor(ctx.renderer_config)
42 hf_processor_mm_kwargs = {} if kwargs_on_init else mm_processor_kwargs
43
44 # Build the image str / prompt based on the number of images we pass
tests/models/multimodal/processing/test_tensor_schema.py
+8 -16
@@ -11,7 +11,7 @@ import pytest
11 import torch.nn as nn
12 from PIL import Image
13
14 -from vllm.config import ModelConfig, VllmConfig, set_current_vllm_config
14 +from vllm.config import ModelConfig, RendererConfig, VllmConfig, set_current_vllm_config
15 from vllm.config.multimodal import (
16 AudioDummyOptions,
17 BaseDummyOptions,
@@ -31,7 +31,6 @@ from vllm.multimodal import MULTIMODAL_REGISTRY, BatchedTensorInputs
31 from vllm.multimodal.processing import BaseMultiModalProcessor, InputProcessingContext
32 from vllm.multimodal.utils import group_mm_kwargs_by_modality
33 from vllm.platforms import current_platform
34 -from vllm.tokenizers import cached_tokenizer_from_config
34 from vllm.utils.collection_utils import is_list_of
35 from vllm.utils.torch_utils import set_default_torch_dtype
36
@@ -150,7 +149,10 @@ def initialize_dummy_model(
149 backend="nccl",
150 )
151 initialize_model_parallel(tensor_model_parallel_size=1)
153 - vllm_config = VllmConfig(model_config=model_config)
152 + vllm_config = VllmConfig(
153 + model_config=model_config,
154 + renderer_config=RendererConfig(model_config=model_config),
155 + )
156 with set_current_vllm_config(vllm_config=vllm_config):
157 with set_default_torch_dtype(model_config.dtype):
158 model = model_cls(vllm_config=vllm_config)
@@ -182,19 +184,12 @@ def test_model_tensor_schema(model_id: str):
184 else:
185 dtype = model_info.dtype
186
185 - model_config = ModelConfig(
187 + renderer_config = model_info.build_renderer_config(
188 model_id,
187 - tokenizer=model_info.tokenizer or model_id,
188 - tokenizer_mode=model_info.tokenizer_mode,
189 - revision=model_info.revision,
190 - trust_remote_code=model_info.trust_remote_code,
189 hf_overrides=hf_overrides_fn,
192 - skip_tokenizer_init=model_info.require_embed_inputs,
193 - enable_prompt_embeds=model_info.require_embed_inputs,
194 - enable_mm_embeds=model_info.require_embed_inputs,
195 - enforce_eager=model_info.enforce_eager,
190 dtype=dtype,
191 )
192 + model_config = renderer_config.model_config
193
194 model_cls = MULTIMODAL_REGISTRY._get_model_cls(model_config)
195 assert supports_multimodal(model_cls)
@@ -212,10 +207,7 @@ def test_model_tensor_schema(model_id: str):
207 if not any(inputs_parse_methods):
208 pytest.skip(f"{model_arch} does not support tensor schema validation.")
209
215 - ctx = InputProcessingContext(
216 - model_config,
217 - tokenizer=cached_tokenizer_from_config(model_config),
218 - )
210 + ctx = InputProcessingContext.from_config(renderer_config)
211 processing_info = factories.info(ctx)
212 supported_mm_limits = processing_info.get_supported_mm_limits()
213 limit_mm_per_prompt = {
tests/models/multimodal/processing/test_transformers.py
+3 -2
@@ -3,7 +3,7 @@
3 import pytest
4
5 from vllm.assets.image import ImageAsset
6 -from vllm.config import ModelConfig
6 +from vllm.config import ModelConfig, RendererConfig
7 from vllm.multimodal import MULTIMODAL_REGISTRY
8
9
@@ -13,8 +13,9 @@ def test_multimodal_processor(model_id):
13 model=model_id,
14 model_impl="transformers",
15 )
16 + renderer_config = RendererConfig(model_config=model_config)
17
17 - mm_processor = MULTIMODAL_REGISTRY.create_processor(model_config)
18 + mm_processor = MULTIMODAL_REGISTRY.create_processor(renderer_config)
19
20 image_pil = ImageAsset("cherry_blossom").pil_image
21 mm_data = {"image": image_pil}
tests/models/multimodal/test_mapping.py
+3 -30
@@ -7,7 +7,6 @@ import torch
7 import transformers
8 from transformers import AutoConfig, PreTrainedModel
9
10 -from vllm.config import ModelConfig
10 from vllm.model_executor.models.utils import WeightsMapper
11 from vllm.multimodal import MULTIMODAL_REGISTRY
12 from vllm.transformers_utils.config import try_get_safetensors_metadata
@@ -50,37 +49,11 @@ def test_hf_model_weights_mapper(model_arch: str):
49 model_info.check_available_online(on_fail="skip")
50 model_info.check_transformers_version(on_fail="skip")
51
53 - is_mistral_model = model_arch in [
54 - "Mistral3ForConditionalGeneration",
55 - "PixtralForConditionalGeneration",
56 - "VoxtralForConditionalGeneration",
57 - ]
58 -
59 - if not is_mistral_model or model_info.tokenizer_mode == "mistral":
60 - tokenizer_mode = model_info.tokenizer_mode
61 - else:
62 - tokenizer_mode = "hf"
63 -
64 - model_id = model_info.default
65 -
66 - model_config = ModelConfig(
67 - model_id,
68 - tokenizer=model_info.tokenizer or model_id,
69 - tokenizer_mode=tokenizer_mode,
70 - config_format="hf",
71 - revision=model_info.revision,
72 - trust_remote_code=model_info.trust_remote_code,
73 - hf_overrides=model_info.hf_overrides,
74 - skip_tokenizer_init=model_info.require_embed_inputs,
75 - enable_prompt_embeds=model_info.require_embed_inputs,
76 - enable_mm_embeds=model_info.require_embed_inputs,
77 - enforce_eager=model_info.enforce_eager,
78 - dtype=model_info.dtype,
79 - )
52 + model_config = model_info.build_model_config(config_format="hf")
53 model_cls = MULTIMODAL_REGISTRY._get_model_cls(model_config)
54
82 - original_weights = create_repo_dummy_weights(model_id)
83 - hf_dummy_model = create_dummy_model(model_id, model_arch)
55 + original_weights = create_repo_dummy_weights(model_config.model)
56 + hf_dummy_model = create_dummy_model(model_config.model, model_arch)
57 hf_converted_weights = hf_dummy_model.named_parameters()
58 hf_converted_buffers = hf_dummy_model.named_buffers()
59 mapper: WeightsMapper = model_cls.hf_to_vllm_mapper
tests/models/registry.py
+32 -1
@@ -9,7 +9,8 @@ import pytest
9 from packaging.version import Version
10 from transformers import __version__ as TRANSFORMERS_VERSION
11
12 -from vllm.config.model import ModelDType, TokenizerMode
12 +from vllm.config.model import ModelConfig, ModelDType
13 +from vllm.config.renderer import RendererConfig, TokenizerMode
14
15
16 @dataclass(frozen=True)
@@ -170,6 +171,36 @@ class _HfExamplesInfo:
171 else:
172 pytest.skip(msg)
173
174 + def build_model_config(self, model: str | None = None, **kwargs) -> ModelConfig:
175 + if model is None:
176 + model = self.default
177 +
178 + return ModelConfig(
179 + **{
180 + "model": model,
181 + "revision": self.revision,
182 + "trust_remote_code": self.trust_remote_code,
183 + "hf_overrides": self.hf_overrides,
184 + "enable_prompt_embeds": self.require_embed_inputs,
185 + "enable_mm_embeds": self.require_embed_inputs,
186 + "enforce_eager": self.enforce_eager,
187 + "dtype": self.dtype,
188 + **kwargs,
189 + }
190 + )
191 +
192 + def build_renderer_config(
193 + self, model: str | None = None, **kwargs
194 + ) -> RendererConfig:
195 + model_config = self.build_model_config(model, **kwargs)
196 +
197 + return RendererConfig(
198 + model_config=model_config,
199 + tokenizer=self.tokenizer or model_config.model,
200 + tokenizer_mode=self.tokenizer_mode,
201 + skip_tokenizer_init=self.require_embed_inputs,
202 + )
203 +
204
205 _TEXT_GENERATION_EXAMPLE_MODELS = {
206 # [Decoder-only]
tests/models/utils.py
+2 -15
@@ -13,7 +13,6 @@ from transformers import PretrainedConfig
13 from vllm.config.model import ModelConfig, ModelDType, RunnerOption
14 from vllm.logprobs import Logprob, PromptLogprobs, SampleLogprobs
15 from vllm.multimodal.processing import InputProcessingContext
16 -from vllm.tokenizers import cached_tokenizer_from_config
16
17 from .. import ci_envs
18 from .registry import HF_EXAMPLE_MODELS
@@ -296,30 +295,18 @@ def build_model_context(
295
296 model_config_kwargs = model_config_kwargs or {}
297 limit_mm_per_prompt = limit_mm_per_prompt or {}
299 - model_config = ModelConfig(
298 + renderer_config = model_info.build_renderer_config(
299 model_id,
300 runner=runner,
302 - tokenizer=model_info.tokenizer or model_id,
303 - tokenizer_mode=model_info.tokenizer_mode,
304 - revision=model_info.revision,
305 - trust_remote_code=model_info.trust_remote_code,
301 dtype=dtype,
302 seed=0,
303 mm_processor_kwargs=mm_processor_kwargs,
304 limit_mm_per_prompt=limit_mm_per_prompt,
305 mm_processor_cache_gb=mm_processor_cache_gb,
311 - hf_overrides=model_info.hf_overrides,
312 - skip_tokenizer_init=model_info.require_embed_inputs,
313 - enable_prompt_embeds=model_info.require_embed_inputs,
314 - enable_mm_embeds=model_info.require_embed_inputs,
315 - enforce_eager=model_info.enforce_eager,
306 **model_config_kwargs,
307 )
308
319 - return InputProcessingContext(
320 - model_config,
321 - tokenizer=cached_tokenizer_from_config(model_config),
322 - )
309 + return InputProcessingContext.from_config(renderer_config)
310
311
312 def check_embeddings_close(
tests/multimodal/test_cache.py
+16 -11
@@ -6,7 +6,7 @@ import numpy as np
6 import pytest
7 import torch
8
9 -from vllm.config import ModelConfig, ParallelConfig, VllmConfig
9 +from vllm.config import ModelConfig, ParallelConfig, RendererConfig, VllmConfig
10 from vllm.multimodal import MULTIMODAL_REGISTRY
11 from vllm.multimodal.cache import (
12 BaseMultiModalProcessorCache,
@@ -110,11 +110,14 @@ def _create_vllm_config(
110 mm_processor_cache_gb: float,
111 enable_ipc: bool,
112 ):
113 + model_config = ModelConfig(
114 + model="llava-hf/llava-onevision-qwen2-0.5b-ov-hf",
115 + mm_processor_cache_gb=mm_processor_cache_gb,
116 + )
117 +
118 return VllmConfig(
114 - model_config=ModelConfig(
115 - model="llava-hf/llava-onevision-qwen2-0.5b-ov-hf",
116 - mm_processor_cache_gb=mm_processor_cache_gb,
117 - ),
119 + model_config=model_config,
120 + renderer_config=RendererConfig(model_config=model_config),
121 parallel_config=ParallelConfig(data_parallel_size=1 if enable_ipc else 2),
122 )
123
@@ -506,13 +509,15 @@ def _run_test_cache_eviction_shm(
509
510
511 def test_cache_eviction_shm_cache():
512 + model_config = ModelConfig(
513 + model="llava-hf/llava-onevision-qwen2-0.5b-ov-hf",
514 + mm_processor_cache_type="shm",
515 + mm_shm_cache_max_object_size_mb=6,
516 + mm_processor_cache_gb=15.2 * MiB_bytes / GiB_bytes,
517 + )
518 vllm_config = VllmConfig(
510 - model_config=ModelConfig(
511 - model="llava-hf/llava-onevision-qwen2-0.5b-ov-hf",
512 - mm_processor_cache_type="shm",
513 - mm_shm_cache_max_object_size_mb=6,
514 - mm_processor_cache_gb=15.2 * MiB_bytes / GiB_bytes,
515 - ),
519 + model_config=model_config,
520 + renderer_config=RendererConfig(model_config=model_config),
521 )
522 sender_cache = ShmObjectStoreSenderCache(vllm_config)
523 receiver_cache = ShmObjectStoreReceiverCache(vllm_config, mp.Lock())
tests/multimodal/test_processing.py
+15 -9
@@ -7,7 +7,7 @@ from contextlib import nullcontext
7 import numpy as np
8 import pytest
9
10 -from vllm.config import ModelConfig
10 +from vllm.config import ModelConfig, RendererConfig
11 from vllm.multimodal import MULTIMODAL_REGISTRY
12 from vllm.multimodal.processing import (
13 InputProcessingContext,
@@ -920,8 +920,9 @@ def test_limit_mm_per_prompt_dummy(model_id, limit, num_supported, is_valid):
920 model=model_id,
921 limit_mm_per_prompt=limit_mm_per_prompt,
922 )
923 + renderer_config = RendererConfig(model_config=model_config)
924
924 - processor = MULTIMODAL_REGISTRY.create_processor(model_config)
925 + processor = MULTIMODAL_REGISTRY.create_processor(renderer_config)
926 processor._supported_mm_limits = {"image": num_supported}
927
928 profiler = MultiModalProfiler(processor)
@@ -955,8 +956,9 @@ def test_limit_mm_per_prompt_apply(model_id, num_images, limit, is_valid):
956 model=model_id,
957 limit_mm_per_prompt=limit_mm_per_prompt,
958 )
959 + renderer_config = RendererConfig(model_config=model_config)
960
959 - processor = MULTIMODAL_REGISTRY.create_processor(model_config)
961 + processor = MULTIMODAL_REGISTRY.create_processor(renderer_config)
962
963 rng = np.random.RandomState(0)
964 image = random_image(rng, min_wh=128, max_wh=256)
@@ -1012,11 +1014,13 @@ def test_hf_processor_init_kwargs(
1014 inference_kwargs,
1015 expected_kwargs,
1016 ):
1015 - ctx = InputProcessingContext(
1016 - model_config=ModelConfig(model_id, mm_processor_kwargs=config_kwargs),
1017 - tokenizer=None,
1017 + model_config = ModelConfig(model_id, mm_processor_kwargs=config_kwargs)
1018 + renderer_config = RendererConfig(
1019 + model_config=model_config,
1020 + tokenizer=model_id,
1021 )
1022
1023 + ctx = InputProcessingContext.from_config(renderer_config)
1024 processor = ctx.get_hf_processor(
1025 DummyProcessor, # type: ignore[arg-type]
1026 **inference_kwargs,
@@ -1045,11 +1049,13 @@ def test_hf_processor_call_kwargs(
1049 inference_kwargs,
1050 expected_kwargs,
1051 ):
1048 - ctx = InputProcessingContext(
1049 - model_config=ModelConfig(model_id, mm_processor_kwargs=config_kwargs),
1050 - tokenizer=None,
1052 + model_config = ModelConfig(model_id, mm_processor_kwargs=config_kwargs)
1053 + renderer_config = RendererConfig(
1054 + model_config=model_config,
1055 + tokenizer=model_id,
1056 )
1057
1058 + ctx = InputProcessingContext.from_config(renderer_config)
1059 processor = ctx.get_hf_processor(DummyProcessor) # type: ignore[arg-type]
1060
1061 result = ctx.call_hf_processor(processor, {}, inference_kwargs)
tests/multimodal/test_registry.py
+3 -1
@@ -31,4 +31,6 @@ def test_supports_multimodal_inputs(model_id, limit_mm_per_prompt, expected):
31 model_id,
32 limit_mm_per_prompt=limit_mm_per_prompt,
33 )
34 - assert MULTIMODAL_REGISTRY.supports_multimodal_inputs(ctx.model_config) is expected
34 + assert (
35 + MULTIMODAL_REGISTRY.supports_multimodal_inputs(ctx.renderer_config) is expected
36 + )
tests/test_config.py
+80 -51
@@ -13,6 +13,7 @@ from vllm.config import (
13 CompilationConfig,
14 ModelConfig,
15 PoolerConfig,
16 + RendererConfig,
17 SchedulerConfig,
18 VllmConfig,
19 update_config,
@@ -476,27 +477,41 @@ def test_load_config_pt_load_map_location(pt_load_map_location):
477 ("deepseek-ai/DeepSeek-R1-Distill-Qwen-7B", 131073, 131072, True),
478 ],
479 )
479 -def test_get_and_verify_max_len(
480 +def test_recalculate_max_model_len(
481 model_id, max_model_len, expected_max_len, should_raise
482 ):
482 - """Test get_and_verify_max_len with different configurations."""
483 + """Test recalculate_max_model_len with different configurations."""
484 model_config = ModelConfig(model_id)
485
486 if should_raise:
487 with pytest.raises(ValueError):
487 - model_config.get_and_verify_max_len(max_model_len)
488 + model_config.recalculate_max_model_len(
489 + max_model_len,
490 + tokenizer=model_id,
491 + tokenizer_revision=None,
492 + )
493 else:
489 - actual_max_len = model_config.get_and_verify_max_len(max_model_len)
490 - assert actual_max_len == expected_max_len
494 + model_config.recalculate_max_model_len(
495 + max_model_len,
496 + tokenizer=model_id,
497 + tokenizer_revision=None,
498 + )
499 + assert model_config.max_model_len == expected_max_len
500
501
493 -class MockConfig:
494 - """Simple mock object for testing maybe_pull_model_tokenizer_for_runai"""
502 +class MockModelConfig:
503 + """Simple mock object for testing maybe_pull_model_for_runai"""
504
496 - def __init__(self, model: str, tokenizer: str):
505 + def __init__(self, model: str):
506 self.model = model
498 - self.tokenizer = tokenizer
499 - self.model_weights = None
507 +
508 +
509 +class MockRendererConfig:
510 + """Simple mock object for testing maybe_pull_tokenizer_for_runai"""
511 +
512 + def __init__(self, model_config: MockModelConfig):
513 + self.model_config = model_config
514 + self.tokenizer = model_config.model
515
516
517 @pytest.mark.parametrize(
@@ -514,59 +529,65 @@ def test_s3_url_model_tokenizer_paths(mock_pull_files, s3_url):
529 mock_pull_files.return_value = None
530
531 # Create first mock and run the method
517 - config1 = MockConfig(model=s3_url, tokenizer=s3_url)
518 - ModelConfig.maybe_pull_model_tokenizer_for_runai(config1, s3_url, s3_url)
532 + model_config1 = MockModelConfig(model=s3_url)
533 + renderer_config1 = MockRendererConfig(model_config=model_config1)
534 + ModelConfig.maybe_pull_model_for_runai(model_config1, s3_url)
535 + RendererConfig.maybe_pull_tokenizer_for_runai(renderer_config1, s3_url)
536
537 # Check that model and tokenizer point to existing directories
521 - assert os.path.exists(config1.model), (
522 - f"Model directory does not exist: {config1.model}"
538 + assert os.path.exists(model_config1.model), (
539 + f"Model directory does not exist: {model_config1.model}"
540 )
524 - assert os.path.isdir(config1.model), (
525 - f"Model path is not a directory: {config1.model}"
541 + assert os.path.isdir(model_config1.model), (
542 + f"Model path is not a directory: {model_config1.model}"
543 )
527 - assert os.path.exists(config1.tokenizer), (
528 - f"Tokenizer directory does not exist: {config1.tokenizer}"
544 + assert os.path.exists(renderer_config1.tokenizer), (
545 + f"Tokenizer directory does not exist: {renderer_config1.tokenizer}"
546 )
530 - assert os.path.isdir(config1.tokenizer), (
531 - f"Tokenizer path is not a directory: {config1.tokenizer}"
547 + assert os.path.isdir(renderer_config1.tokenizer), (
548 + f"Tokenizer path is not a directory: {renderer_config1.tokenizer}"
549 )
550
551 # Verify that the paths are different from the original S3 URL
535 - assert config1.model != s3_url, "Model path should be converted to local directory"
536 - assert config1.tokenizer != s3_url, (
552 + assert model_config1.model != s3_url, (
553 + "Model path should be converted to local directory"
554 + )
555 + assert renderer_config1.tokenizer != s3_url, (
556 "Tokenizer path should be converted to local directory"
557 )
558
559 # Store the original paths
541 - created_model_dir = config1.model
542 - create_tokenizer_dir = config1.tokenizer
560 + created_model_dir = model_config1.model
561 + create_tokenizer_dir = renderer_config1.tokenizer
562
563 # Create a new mock and run the method with the same S3 URL
545 - config2 = MockConfig(model=s3_url, tokenizer=s3_url)
546 - ModelConfig.maybe_pull_model_tokenizer_for_runai(config2, s3_url, s3_url)
564 + model_config2 = MockModelConfig(model=s3_url)
565 + renderer_config2 = MockRendererConfig(model_config=model_config2)
566 + ModelConfig.maybe_pull_model_for_runai(model_config2, s3_url)
567 + RendererConfig.maybe_pull_tokenizer_for_runai(renderer_config2, s3_url)
568
569 # Check that the new directories exist
549 - assert os.path.exists(config2.model), (
550 - f"Model directory does not exist: {config2.model}"
570 + assert os.path.exists(model_config2.model), (
571 + f"Model directory does not exist: {model_config2.model}"
572 )
552 - assert os.path.isdir(config2.model), (
553 - f"Model path is not a directory: {config2.model}"
573 + assert os.path.isdir(model_config2.model), (
574 + f"Model path is not a directory: {model_config2.model}"
575 )
555 - assert os.path.exists(config2.tokenizer), (
556 - f"Tokenizer directory does not exist: {config2.tokenizer}"
576 + assert os.path.exists(renderer_config2.tokenizer), (
577 + f"Tokenizer directory does not exist: {renderer_config2.tokenizer}"
578 )
558 - assert os.path.isdir(config2.tokenizer), (
559 - f"Tokenizer path is not a directory: {config2.tokenizer}"
579 + assert os.path.isdir(renderer_config2.tokenizer), (
580 + f"Tokenizer path is not a directory: {renderer_config2.tokenizer}"
581 )
582
583 # Verify that the paths are deterministic (same as before)
563 - assert config2.model == created_model_dir, (
584 + assert model_config2.model == created_model_dir, (
585 f"Model paths are not deterministic. "
565 - f"Original: {created_model_dir}, New: {config2.model}"
586 + f"Original: {created_model_dir}, New: {model_config2.model}"
587 )
567 - assert config2.tokenizer == create_tokenizer_dir, (
588 + assert renderer_config2.tokenizer == create_tokenizer_dir, (
589 f"Tokenizer paths are not deterministic. "
569 - f"Original: {create_tokenizer_dir}, New: {config2.tokenizer}"
590 + f"Original: {create_tokenizer_dir}, New: {renderer_config2.tokenizer}"
591 )
592
593
@@ -580,28 +601,36 @@ def test_s3_url_different_models_create_different_directories(mock_pull_files):
601 s3_url2 = "s3://example-bucket-2/model/"
602
603 # Create mocks with different S3 URLs and run the method
583 - config1 = MockConfig(model=s3_url1, tokenizer=s3_url1)
584 - ModelConfig.maybe_pull_model_tokenizer_for_runai(config1, s3_url1, s3_url1)
604 + model_config1 = MockModelConfig(model=s3_url1)
605 + renderer_config1 = MockRendererConfig(model_config=model_config1)
606 + ModelConfig.maybe_pull_model_for_runai(model_config1, s3_url1)
607 + RendererConfig.maybe_pull_tokenizer_for_runai(renderer_config1, s3_url1)
608
586 - config2 = MockConfig(model=s3_url2, tokenizer=s3_url2)
587 - ModelConfig.maybe_pull_model_tokenizer_for_runai(config2, s3_url2, s3_url2)
609 + model_config2 = MockModelConfig(model=s3_url2)
610 + renderer_config2 = MockRendererConfig(model_config=model_config2)
611 + ModelConfig.maybe_pull_model_for_runai(model_config2, s3_url2)
612 + RendererConfig.maybe_pull_tokenizer_for_runai(renderer_config2, s3_url2)
613
614 # Verify that different URLs produce different directories
590 - assert config1.model != config2.model, (
615 + assert model_config1.model != model_config2.model, (
616 f"Different S3 URLs should create different model directories. "
592 - f"URL1 model: {config1.model}, URL2 model: {config2.model}"
617 + f"URL1 model: {model_config1.model}, URL2 model: {model_config2.model}"
618 )
594 - assert config1.tokenizer != config2.tokenizer, (
619 + assert renderer_config1.tokenizer != renderer_config2.tokenizer, (
620 f"Different S3 URLs should create different tokenizer directories. "
596 - f"URL1 tokenizer: {config1.tokenizer}, "
597 - f"URL2 tokenizer: {config2.tokenizer}"
621 + f"URL1 tokenizer: {renderer_config1.tokenizer}, "
622 + f"URL2 tokenizer: {renderer_config2.tokenizer}"
623 )
624
625 # Verify that both sets of directories exist
601 - assert os.path.exists(config1.model) and os.path.isdir(config1.model)
602 - assert os.path.exists(config1.tokenizer) and os.path.isdir(config1.tokenizer)
603 - assert os.path.exists(config2.model) and os.path.isdir(config2.model)
604 - assert os.path.exists(config2.tokenizer) and os.path.isdir(config2.tokenizer)
626 + assert os.path.exists(model_config1.model) and os.path.isdir(model_config1.model)
627 + assert os.path.exists(renderer_config1.tokenizer) and os.path.isdir(
628 + renderer_config1.tokenizer
629 + )
630 + assert os.path.exists(model_config2.model) and os.path.isdir(model_config2.model)
631 + assert os.path.exists(renderer_config2.tokenizer) and os.path.isdir(
632 + renderer_config2.tokenizer
633 + )
634
635
636 @pytest.mark.parametrize(
tests/test_inputs.py
+4 -3
@@ -3,7 +3,7 @@
3
4 import pytest
5
6 -from vllm.config import ModelConfig
6 +from vllm.config import ModelConfig, RendererConfig
7 from vllm.inputs import zip_enc_dec_prompts
8 from vllm.inputs.parse import parse_raw_prompts
9 from vllm.inputs.preprocess import InputPreprocessor
@@ -108,8 +108,9 @@ def test_zip_enc_dec_prompts(mm_processor_kwargs, expected_mm_kwargs):
108 )
109 def test_preprocessor_always_mm_code_path(model_id, prompt):
110 model_config = ModelConfig(model=model_id)
111 - tokenizer = init_tokenizer_from_config(model_config)
112 - input_preprocessor = InputPreprocessor(model_config, tokenizer)
111 + renderer_config = RendererConfig(model_config=model_config)
112 + tokenizer = init_tokenizer_from_config(renderer_config)
113 + input_preprocessor = InputPreprocessor(renderer_config, tokenizer)
114
115 # HF processor adds sep token
116 sep_token_id = tokenizer.vocab[tokenizer.sep_token]
tests/v1/attention/utils.py
+2
@@ -16,6 +16,7 @@ from vllm.config import (
16 LoadConfig,
17 ModelConfig,
18 ParallelConfig,
19 + RendererConfig,
20 SchedulerConfig,
21 VllmConfig,
22 )
@@ -216,6 +217,7 @@ def create_vllm_config(
217
218 return VllmConfig(
219 model_config=model_config,
220 + renderer_config=RendererConfig(model_config=model_config),
221 cache_config=cache_config,
222 parallel_config=parallel_config,
223 scheduler_config=scheduler_config,
tests/v1/core/test_kv_cache_utils.py
+16 -4
@@ -8,7 +8,7 @@ import pytest
8 import torch
9
10 import vllm.v1.core.kv_cache_utils as kv_cache_utils
11 -from vllm.config import ModelConfig, SchedulerConfig, VllmConfig
11 +from vllm.config import ModelConfig, RendererConfig, SchedulerConfig, VllmConfig
12 from vllm.lora.request import LoRARequest
13 from vllm.multimodal.inputs import (
14 MultiModalFeatureSpec,
@@ -667,7 +667,10 @@ def test_metrics_empty_stats():
667
668 def test_get_kv_cache_configs_multiple_workers():
669 model_config = ModelConfig(max_model_len=16)
670 - vllm_config = VllmConfig(model_config=model_config)
670 + vllm_config = VllmConfig(
671 + model_config=model_config,
672 + renderer_config=RendererConfig(model_config=model_config),
673 + )
674
675 ref_kv_cache_spec = new_kv_cache_spec()
676 same_kv_cache_specs = [
@@ -1136,6 +1139,7 @@ def test_estimate_max_model_len(model_id, max_model_len, want_estimated_max_len)
1139
1140 vllm_config = VllmConfig(
1141 model_config=model_config,
1142 + renderer_config=RendererConfig(model_config=model_config),
1143 scheduler_config=scheduler_config,
1144 )
1145
@@ -1175,6 +1179,7 @@ def test_get_max_concurrency_for_kv_cache_config():
1179
1180 vllm_config = VllmConfig(
1181 model_config=model_config,
1182 + renderer_config=RendererConfig(model_config=model_config),
1183 scheduler_config=scheduler_config,
1184 )
1185
@@ -1293,7 +1298,10 @@ def test_allocate_with_lookahead():
1298 def test_get_kv_cache_config_one_worker():
1299 # pass max_model_len to pass check_enough_kv_cache_memory
1300 model_config = ModelConfig(max_model_len=16)
1296 - vllm_config = VllmConfig(model_config=model_config)
1301 + vllm_config = VllmConfig(
1302 + model_config=model_config,
1303 + renderer_config=RendererConfig(model_config=model_config),
1304 + )
1305
1306 mem_per_block_per_layer = 16 * 2 * 64 * 4 * 2
1307 # all layers are full attention -> single group
@@ -1584,7 +1592,11 @@ def test_get_kv_cache_config_one_worker():
1592
1593 def test_get_kv_cache_configs_attention_free():
1594 kv_cache_specs: dict[str, KVCacheSpec] = {}
1587 - vllm_config = VllmConfig(model_config=ModelConfig(max_model_len=16))
1595 + model_config = ModelConfig(max_model_len=16)
1596 + vllm_config = VllmConfig(
1597 + model_config=model_config,
1598 + renderer_config=RendererConfig(model_config=model_config),
1599 + )
1600 kv_cache_configs = get_kv_cache_configs(vllm_config, [kv_cache_specs], [0])
1601 assert kv_cache_configs == [
1602 KVCacheConfig(
tests/v1/core/test_scheduler.py
+2
@@ -11,6 +11,7 @@ from vllm.config import (
11 ECTransferConfig,
12 KVTransferConfig,
13 ModelConfig,
14 + RendererConfig,
15 SchedulerConfig,
16 SpeculativeConfig,
17 VllmConfig,
@@ -1563,6 +1564,7 @@ def create_scheduler_with_priority(
1564 vllm_config = VllmConfig(
1565 scheduler_config=scheduler_config,
1566 model_config=model_config,
1567 + renderer_config=RendererConfig(model_config=model_config),
1568 cache_config=cache_config,
1569 kv_transfer_config=kv_transfer_config,
1570 speculative_config=speculative_config,
tests/v1/core/utils.py
+2
@@ -9,6 +9,7 @@ from vllm.config import (
9 ECTransferConfig,
10 KVTransferConfig,
11 ModelConfig,
12 + RendererConfig,
13 SchedulerConfig,
14 SpeculativeConfig,
15 VllmConfig,
@@ -132,6 +133,7 @@ def create_scheduler(
133 vllm_config = VllmConfig(
134 scheduler_config=scheduler_config,
135 model_config=model_config,
136 + renderer_config=RendererConfig(model_config=model_config),
137 cache_config=cache_config,
138 kv_transfer_config=kv_transfer_config,
139 speculative_config=speculative_config,
tests/v1/engine/test_engine_core.py
+2
@@ -15,6 +15,7 @@ from vllm.config import (
15 ECTransferConfig,
16 KVTransferConfig,
17 ModelConfig,
18 + RendererConfig,
19 SchedulerConfig,
20 VllmConfig,
21 )
@@ -522,6 +523,7 @@ def test_encoder_instance_zero_kv_cache(
523
524 vllm_config = VllmConfig(
525 model_config=model_config,
526 + renderer_config=RendererConfig(model_config=model_config),
527 cache_config=cache_config,
528 scheduler_config=scheduler_config,
529 kv_transfer_config=kv_transfer_config,
tests/v1/engine/test_process_multi_modal_uuids.py
+15 -9
@@ -5,7 +5,14 @@ import pytest
5
6 from vllm.assets.image import ImageAsset
7 from vllm.assets.video import VideoAsset
8 -from vllm.config import CacheConfig, DeviceConfig, ModelConfig, VllmConfig
8 +from vllm.config import (
9 + CacheConfig,
10 + DeviceConfig,
11 + ModelConfig,
12 + MultiModalConfig,
13 + RendererConfig,
14 + VllmConfig,
15 +)
16 from vllm.sampling_params import SamplingParams
17 from vllm.v1.engine import input_processor as input_processor_mod
18 from vllm.v1.engine.input_processor import InputProcessor
@@ -44,22 +51,21 @@ def _mock_input_processor(
51 monkeypatch.setattr(VllmConfig, "__post_init__", lambda self: None, raising=True)
52
53 model_config = ModelConfig(
47 - skip_tokenizer_init=True,
54 max_model_len=128,
55 mm_processor_cache_gb=mm_cache_gb,
56 generation_config="vllm",
51 - tokenizer="dummy",
57 )
58 + model_config.multimodal_config = MultiModalConfig(mm_processor_cache_gb=mm_cache_gb)
59
54 - # Minimal multimodal_config to satisfy references in
55 - # Processor.process_inputs.
56 - class _MockMMConfig:
57 - def __init__(self, gb: float):
58 - self.mm_processor_cache_gb = gb
60 + renderer_config = RendererConfig(
61 + model_config=model_config,
62 + tokenizer="dummy",
63 + skip_tokenizer_init=True,
64 + )
65
60 - model_config.multimodal_config = _MockMMConfig(mm_cache_gb) # type: ignore[attr-defined]
66 vllm_config = VllmConfig(
67 model_config=model_config,
68 + renderer_config=renderer_config,
69 cache_config=CacheConfig(enable_prefix_caching=enable_prefix_caching),
70 device_config=DeviceConfig(device="cpu"),
71 )
tests/v1/kv_connector/unit/utils.py
+2
@@ -15,6 +15,7 @@ from vllm.config import (
15 DeviceConfig,
16 KVTransferConfig,
17 ModelConfig,
18 + RendererConfig,
19 SchedulerConfig,
20 VllmConfig,
21 )
@@ -127,6 +128,7 @@ def create_vllm_config(
128 return VllmConfig(
129 scheduler_config=scheduler_config,
130 model_config=model_config,
131 + renderer_config=RendererConfig(model_config=model_config),
132 cache_config=cache_config,
133 kv_transfer_config=kv_transfer_config,
134 device_config=DeviceConfig("cpu"),
tests/v1/spec_decode/test_eagle.py
+2
@@ -19,6 +19,7 @@ from vllm.config import (
19 DeviceConfig,
20 ModelConfig,
21 ParallelConfig,
22 + RendererConfig,
23 SchedulerConfig,
24 SpeculativeConfig,
25 VllmConfig,
@@ -61,6 +62,7 @@ def _create_proposer(
62
63 vllm_config = VllmConfig(
64 model_config=model_config,
65 + renderer_config=RendererConfig(model_config=model_config),
66 cache_config=CacheConfig(),
67 speculative_config=speculative_config,
68 device_config=DeviceConfig(device=current_platform.device_type),
tests/v1/spec_decode/test_mtp.py
+2
@@ -18,6 +18,7 @@ from vllm.config import (
18 DeviceConfig,
19 ModelConfig,
20 ParallelConfig,
21 + RendererConfig,
22 SchedulerConfig,
23 SpeculativeConfig,
24 VllmConfig,
@@ -46,6 +47,7 @@ def _create_mtp_proposer(num_speculative_tokens: int) -> EagleProposer:
47
48 vllm_config = VllmConfig(
49 model_config=model_config,
50 + renderer_config=RendererConfig(model_config=model_config),
51 cache_config=CacheConfig(),
52 speculative_config=speculative_config,
53 device_config=DeviceConfig(device=current_platform.device_type),
tests/v1/spec_decode/test_ngram.py
+2
@@ -4,6 +4,7 @@ import numpy as np
4
5 from vllm.config import (
6 ModelConfig,
7 + RendererConfig,
8 SpeculativeConfig,
9 VllmConfig,
10 )
@@ -69,6 +70,7 @@ def test_ngram_proposer():
70 return NgramProposer(
71 vllm_config=VllmConfig(
72 model_config=model_config,
73 + renderer_config=RendererConfig(model_config=model_config),
74 speculative_config=SpeculativeConfig(
75 prompt_lookup_min=min_n,
76 prompt_lookup_max=max_n,
tests/v1/structured_output/test_backend_guidance.py
+9 -3
@@ -6,7 +6,7 @@ from concurrent.futures import Future
6 import pytest
7 from transformers import AutoTokenizer
8
9 -from vllm.config import StructuredOutputsConfig, VllmConfig
9 +from vllm.config import RendererConfig, StructuredOutputsConfig, VllmConfig
10 from vllm.config.model import ModelConfig
11 from vllm.config.parallel import ParallelConfig
12 from vllm.config.speculative import SpeculativeConfig
@@ -72,8 +72,11 @@ def test_backend_guidance_rollback_terminated():
72 def test_grammar_bitmask_with_specdec():
73 tokenizer = AutoTokenizer.from_pretrained(TOKENIZER)
74 prompt = tokenizer.encode('{"a": "b"}')
75 +
76 + model_config = ModelConfig(tokenizer=TOKENIZER)
77 vllm_config = VllmConfig(
76 - model_config=ModelConfig(tokenizer=TOKENIZER),
78 + model_config=model_config,
79 + renderer_config=RendererConfig(model_config=model_config, tokenizer=TOKENIZER),
80 structured_outputs_config=StructuredOutputsConfig(backend="guidance"),
81 speculative_config=SpeculativeConfig(model="[ngram]", num_speculative_tokens=3),
82 )
@@ -137,8 +140,11 @@ def test_grammar_init_async_and_sync(async_grammar):
140
141 # Use "external_launcher" for sync mode, None for async mode
142 executor_backend = None if async_grammar else "external_launcher"
143 +
144 + model_config = ModelConfig(tokenizer=TOKENIZER)
145 vllm_config = VllmConfig(
141 - model_config=ModelConfig(tokenizer=TOKENIZER),
146 + model_config=model_config,
147 + renderer_config=RendererConfig(model_config=model_config, tokenizer=TOKENIZER),
148 structured_outputs_config=StructuredOutputsConfig(backend="guidance"),
149 parallel_config=ParallelConfig(distributed_executor_backend=executor_backend),
150 )
tests/v1/structured_output/test_reasoning_structured_output.py
+21 -14
@@ -7,7 +7,7 @@ from unittest.mock import Mock
7
8 import pytest
9
10 -from vllm.config import ModelConfig, SchedulerConfig, VllmConfig
10 +from vllm.config import ModelConfig, RendererConfig, SchedulerConfig, VllmConfig
11 from vllm.reasoning import ReasoningParser
12 from vllm.v1.request import Request
13 from vllm.v1.structured_output import StructuredOutputManager
@@ -17,19 +17,26 @@ class TestReasoningStructuredOutput:
17 """Test reasoning-aware structured output functionality."""
18
19 @pytest.fixture
20 - def mock_model_config(self):
21 - """Create a mock ModelConfig."""
22 - config = Mock(spec=ModelConfig)
23 - config.skip_tokenizer_init = True # Skip tokenizer init to avoid network calls
24 - config.get_vocab_size = Mock(return_value=50000)
20 + def mock_renderer_config(self):
21 + """Create a mock RendererConfig."""
22 + renderer_config = Mock(spec=RendererConfig)
23 + renderer_config.skip_tokenizer_init = (
24 + True # Skip tokenizer init to avoid network calls
25 + )
26 +
27 + model_config = Mock(spec=ModelConfig)
28 + model_config.get_vocab_size = Mock(return_value=50000)
29 + model_config.trust_remote_code = False
30 # Add missing runner_type attribute that tokenizer initialization expects
26 - config.runner_type = "generate"
31 + model_config.runner_type = "generate"
32 + renderer_config.model_config = model_config
33 +
34 # Add other attributes that tokenizer initialization might need
28 - config.tokenizer = "test-tokenizer"
29 - config.tokenizer_mode = "auto"
30 - config.trust_remote_code = False
31 - config.tokenizer_revision = None
32 - return config
35 + renderer_config.tokenizer = "test-tokenizer"
36 + renderer_config.tokenizer_mode = "auto"
37 + renderer_config.tokenizer_revision = None
38 +
39 + return renderer_config
40
41 @pytest.fixture
42 def mock_scheduler_config(self):
@@ -39,10 +46,10 @@ class TestReasoningStructuredOutput:
46 return config
47
48 @pytest.fixture
42 - def mock_vllm_config(self, mock_model_config, mock_scheduler_config):
49 + def mock_vllm_config(self, mock_renderer_config, mock_scheduler_config):
50 """Create a mock VllmConfig."""
51 config = Mock(spec=VllmConfig)
45 - config.model_config = mock_model_config
52 + config.renderer_config = mock_renderer_config
53 config.scheduler_config = mock_scheduler_config
54 config.structured_outputs_config = Mock()
55 config.structured_outputs_config.reasoning_parser = None
tests/v1/tpu/worker/test_tpu_model_runner.py
+2
@@ -7,6 +7,7 @@ from vllm.attention.layer import Attention
7 from vllm.config import (
8 CacheConfig,
9 ModelConfig,
10 + RendererConfig,
11 SchedulerConfig,
12 VllmConfig,
13 set_current_vllm_config,
@@ -45,6 +46,7 @@ def get_vllm_config():
46 )
47 vllm_config = VllmConfig(
48 model_config=model_config,
49 + renderer_config=RendererConfig(model_config=model_config),
50 cache_config=cache_config,
51 scheduler_config=scheduler_config,
52 )
tests/v1/worker/test_gpu_model_runner.py
+3
@@ -13,6 +13,7 @@ from vllm.config import (
13 CacheConfig,
14 ModelConfig,
15 ParallelConfig,
16 + RendererConfig,
17 SchedulerConfig,
18 VllmConfig,
19 set_current_vllm_config,
@@ -101,6 +102,7 @@ def get_vllm_config():
102 parallel_config = ParallelConfig()
103 vllm_config = VllmConfig(
104 model_config=model_config,
105 + renderer_config=RendererConfig(model_config=model_config),
106 cache_config=cache_config,
107 scheduler_config=scheduler_config,
108 parallel_config=parallel_config,
@@ -811,6 +813,7 @@ def test_hybrid_attention_mamba_tensor_shapes():
813 attention_config = AttentionConfig(backend=AttentionBackendEnum.FLASHINFER)
814 vllm_config = VllmConfig(
815 model_config=model_config,
816 + renderer_config=RendererConfig(model_config=model_config),
817 cache_config=cache_config,
818 scheduler_config=scheduler_config,
819 parallel_config=parallel_config,
vllm/config/__init__.py
+3
@@ -24,6 +24,7 @@ from vllm.config.multimodal import MultiModalConfig
24 from vllm.config.observability import ObservabilityConfig
25 from vllm.config.parallel import EPLBConfig, ParallelConfig
26 from vllm.config.pooler import PoolerConfig
27 +from vllm.config.renderer import RendererConfig
28 from vllm.config.scheduler import SchedulerConfig
29 from vllm.config.speculative import SpeculativeConfig
30 from vllm.config.speech_to_text import SpeechToTextConfig
@@ -81,6 +82,8 @@ __all__ = [
82 "ParallelConfig",
83 # From vllm.config.pooler
84 "PoolerConfig",
85 + # From vllm.config.renderer
86 + "RendererConfig",
87 # From vllm.config.scheduler
88 "SchedulerConfig",
89 # From vllm.config.speculative
vllm/config/model.py
+31 -110
@@ -36,7 +36,6 @@ from vllm.transformers_utils.config import (
36 uses_xdrope_dim,
37 )
38 from vllm.transformers_utils.gguf_utils import (
39 - is_gguf,
39 is_remote_gguf,
40 maybe_patch_hf_config_from_gguf,
41 split_remote_gguf,
@@ -83,7 +82,6 @@ TaskOption = Literal[
82 "transcription",
83 "draft",
84 ]
86 -TokenizerMode = Literal["auto", "hf", "slow", "mistral", "deepseek_v32"]
85 ModelDType = Literal["auto", "half", "float16", "bfloat16", "float", "float32"]
86 LogprobsMode = Literal[
87 "raw_logits", "raw_logprobs", "processed_logits", "processed_logprobs"
@@ -131,18 +129,6 @@ class ModelConfig:
129
130 Note that the model may support other tasks using the same model runner.
131 """
134 - tokenizer: SkipValidation[str] = None # type: ignore
135 - """Name or path of the Hugging Face tokenizer to use. If unspecified, model
136 - name or path will be used."""
137 - tokenizer_mode: TokenizerMode | str = "auto"
138 - """Tokenizer mode:\n
139 - - "auto" will use the tokenizer from `mistral_common` for Mistral models
140 - if available, otherwise it will use the "hf" tokenizer.\n
141 - - "hf" will use the fast tokenizer if available.\n
142 - - "slow" will always use the slow tokenizer.\n
143 - - "mistral" will always use the tokenizer from `mistral_common`.\n
144 - - "deepseek_v32" will always use the tokenizer from `deepseek_v32`.\n
145 - - Other custom values can be supported via plugins."""
132 trust_remote_code: bool = False
133 """Trust remote code (e.g., from HuggingFace) when downloading the model
134 and tokenizer."""
@@ -168,13 +154,6 @@ class ModelConfig:
154 hf_config_path: str | None = None
155 """Name or path of the Hugging Face config to use. If unspecified, model
156 name or path will be used."""
171 - allowed_local_media_path: str = ""
172 - """Allowing API requests to read local images or videos from directories
173 - specified by the server file system. This is a security risk. Should only
174 - be enabled in trusted environments."""
175 - allowed_media_domains: list[str] | None = None
176 - """If set, only media URLs that belong to this domain can be used for
177 - multi-modal inputs. """
157 revision: str | None = None
158 """The specific model version to use. It can be a branch name, a tag name,
159 or a commit id. If unspecified, will use the default version."""
@@ -182,10 +161,6 @@ class ModelConfig:
161 """The specific revision to use for the model code on the Hugging Face Hub.
162 It can be a branch name, a tag name, or a commit id. If unspecified, will
163 use the default version."""
185 - tokenizer_revision: str | None = None
186 - """The specific revision to use for the tokenizer on the Hugging Face Hub.
187 - It can be a branch name, a tag name, or a commit id. If unspecified, will
188 - use the default version."""
164 max_model_len: SkipValidation[int] = None # type: ignore
165 """Model context length (prompt and output). If unspecified, will be
166 automatically derived from the model config.
@@ -230,10 +205,6 @@ class ModelConfig:
205 preventing potential numerical issues. Note that even if this is set to
206 False, cascade attention will be only used when the heuristic tells that
207 it's beneficial."""
233 - skip_tokenizer_init: bool = False
234 - """Skip initialization of tokenizer and detokenizer. Expects valid
235 - `prompt_token_ids` and `None` for prompt from the input. The generated
236 - output will contain token ids."""
208 enable_prompt_embeds: bool = False
209 """If `True`, enables passing text embeddings as inputs via the
210 `prompt_embeds` key.
@@ -294,8 +265,6 @@ class ModelConfig:
265 logits_processors: list[str | type[LogitsProcessor]] | None = None
266 """One or more logits processors' fully-qualified class names or class
267 definitions"""
297 - io_processor_plugin: str | None = None
298 - """IOProcessor plugin name to load at model startup"""
268
269 # Pooler config
270 pooler_config: PoolerConfig | None = None
@@ -308,7 +277,6 @@ class ModelConfig:
277 from the architecture of `self.model`."""
278 limit_mm_per_prompt: InitVar[dict[str, int | dict[str, int]] | None] = None
279 enable_mm_embeds: InitVar[bool | None] = None
311 - media_io_kwargs: InitVar[dict[str, dict[str, Any]] | None] = None
280 mm_processor_kwargs: InitVar[dict[str, Any] | None] = None
281 mm_processor_cache_gb: InitVar[float | None] = None
282 mm_processor_cache_type: InitVar[MMCacheType | None] = None
@@ -335,18 +303,12 @@ class ModelConfig:
303 "runner",
304 "convert",
305 "task",
338 - "tokenizer",
339 - "tokenizer_mode",
306 "seed",
307 "hf_config_path",
342 - "allowed_local_media_path",
343 - "allowed_media_domains",
344 - "tokenizer_revision",
308 "spec_target_max_model_len",
309 "enforce_eager",
310 "logprobs_mode",
311 "disable_cascade_attn",
349 - "skip_tokenizer_init",
312 "served_model_name",
313 "config_format",
314 "hf_token",
@@ -354,11 +316,9 @@ class ModelConfig:
316 "logits_processor_pattern",
317 "override_attention_dtype",
318 "logits_processors",
357 - "io_processor_plugin",
319 "pooler_config",
320 "multimodal_config",
321 "limit_mm_per_prompt",
361 - "media_io_kwargs",
322 "mm_processor_kwargs",
323 "mm_processor_cache_gb",
324 "mm_processor_cache_type",
@@ -423,7 +383,6 @@ class ModelConfig:
383 # Multimodal config init vars
384 limit_mm_per_prompt: dict[str, int | dict[str, int]] | None,
385 enable_mm_embeds: bool | None,
426 - media_io_kwargs: dict[str, dict[str, Any]] | None,
386 mm_processor_kwargs: dict[str, Any] | None,
387 mm_processor_cache_gb: float | None,
388 mm_processor_cache_type: MMCacheType | None,
@@ -438,13 +397,8 @@ class ModelConfig:
397 self.served_model_name = get_served_model_name(
398 self.model, self.served_model_name
399 )
441 - self.model = maybe_model_redirect(self.model)
442 - # The tokenizer is consistent with the model by default.
443 - if self.tokenizer is None:
444 - self.tokenizer = self.model
445 - if self.tokenizer_revision is None:
446 - self.tokenizer_revision = self.revision
447 - self.tokenizer = maybe_model_redirect(self.tokenizer)
400 + self.original_model = self.model
401 + self.model = maybe_model_redirect(self.original_model)
402
403 if isinstance(self.hf_config_path, str):
404 self.hf_config_path = maybe_model_redirect(self.hf_config_path)
@@ -465,7 +419,7 @@ class ModelConfig:
419 hf_overrides_kw[key] = value
420 hf_overrides_fn = None
421
468 - self.maybe_pull_model_tokenizer_for_runai(self.model, self.tokenizer)
422 + self.maybe_pull_model_for_runai(self.model)
423
424 from vllm.platforms import current_platform
425
@@ -648,7 +602,8 @@ class ModelConfig:
602 )
603
604 self.original_max_model_len = self.max_model_len
651 - self.max_model_len = self.get_and_verify_max_len(self.max_model_len)
605 + self.recalculate_max_model_len(self.original_max_model_len)
606 +
607 # Init multimodal config if needed
608 if self._model_info.supports_multimodal:
609 if (
@@ -664,7 +619,6 @@ class ModelConfig:
619 mm_config_kwargs = dict(
620 limit_per_prompt=limit_mm_per_prompt,
621 enable_mm_embeds=enable_mm_embeds,
667 - media_io_kwargs=media_io_kwargs,
622 mm_processor_kwargs=mm_processor_kwargs,
623 mm_processor_cache_gb=mm_processor_cache_gb,
624 mm_processor_cache_type=mm_processor_cache_type,
@@ -682,16 +636,8 @@ class ModelConfig:
636
637 self.multimodal_config = MultiModalConfig(**mm_config_kwargs)
638
685 - # Multimodal GGUF models must use original repo for mm processing
686 - if is_gguf(self.tokenizer) and self.is_multimodal_model:
687 - raise ValueError(
688 - "Loading a multimodal GGUF model needs to use original "
689 - "tokenizer. Please specify the unquantized hf model's "
690 - "repo name or path using the --tokenizer argument."
691 - )
692 -
639 if self.disable_sliding_window:
694 - # Set after get_and_verify_max_len to ensure that max_model_len
640 + # Set after recalculate_max_model_len to ensure that max_model_len
641 # can be correctly capped to sliding window size
642 self.hf_text_config.sliding_window = None
643
@@ -715,10 +661,9 @@ class ModelConfig:
661
662 @model_validator(mode="after")
663 def validate_model_config_after(self: "ModelConfig") -> "ModelConfig":
718 - if not isinstance(self.tokenizer, str):
719 - raise ValueError("tokenizer must be a string after __post_init__.")
664 if not isinstance(self.max_model_len, int):
665 raise ValueError("max_model_len must be an integer after __post_init__.")
666 +
667 return self
668
669 def _get_transformers_backend_cls(self) -> str:
@@ -767,49 +712,17 @@ class ModelConfig:
712 """The architecture vllm actually used."""
713 return self._architecture
714
770 - def maybe_pull_model_tokenizer_for_runai(self, model: str, tokenizer: str) -> None:
771 - """Pull model/tokenizer from Object Storage to temporary
772 - directory when needed.
773 -
774 - Args:
775 - model: Model name or path
776 - tokenizer: Tokenizer name or path
777 - """
778 -
779 - if not (is_runai_obj_uri(model) or is_runai_obj_uri(tokenizer)):
715 + def maybe_pull_model_for_runai(self, model: str) -> None:
716 + """Pull model from Object Storage to temporary directory when needed."""
717 + if not is_runai_obj_uri(model):
718 return
719
782 - if is_runai_obj_uri(model):
783 - object_storage_model = ObjectStorageModel(url=model)
784 - object_storage_model.pull_files(
785 - model, allow_pattern=["*.model", "*.py", "*.json"]
786 - )
787 - self.model_weights = model
788 - self.model = object_storage_model.dir
789 -
790 - # If tokenizer is same as model, download to same directory
791 - if model == tokenizer:
792 - object_storage_model.pull_files(
793 - model,
794 - ignore_pattern=[
795 - "*.pt",
796 - "*.safetensors",
797 - "*.bin",
798 - "*.tensors",
799 - "*.pth",
800 - ],
801 - )
802 - self.tokenizer = object_storage_model.dir
803 - return
804 -
805 - # Only download tokenizer if needed and not already handled
806 - if is_runai_obj_uri(tokenizer):
807 - object_storage_tokenizer = ObjectStorageModel(url=tokenizer)
808 - object_storage_tokenizer.pull_files(
809 - model,
810 - ignore_pattern=["*.pt", "*.safetensors", "*.bin", "*.tensors", "*.pth"],
811 - )
812 - self.tokenizer = object_storage_tokenizer.dir
720 + object_storage_model = ObjectStorageModel(url=model)
721 + object_storage_model.pull_files(
722 + model, allow_pattern=["*.model", "*.py", "*.json"]
723 + )
724 + self.model_weights = model
725 + self.model = object_storage_model.dir
726
727 def _get_encoder_config(self):
728 model = self.model
@@ -1712,30 +1625,38 @@ class ModelConfig:
1625 return dense_modules[-1]["out_features"]
1626 return self.get_hidden_size()
1627
1715 - def get_and_verify_max_len(self, max_model_len: int):
1628 + def recalculate_max_model_len(
1629 + self,
1630 + original_max_model_len: int | None,
1631 + *,
1632 + tokenizer: str | None = None,
1633 + tokenizer_revision: str | None = None,
1634 + ) -> None:
1635 # Consider max_model_len in tokenizer_config only when
1636 # pooling models use absolute position_embedding.
1637 + # NOTE: For simplicity we assume `args.model == args.tokenizer`
1638 + # since this is
1639 tokenizer_config = None
1640 if (
1641 self.runner_type == "pooling"
1642 and getattr(self.hf_config, "position_embedding_type", "") == "absolute"
1643 ):
1644 tokenizer_config = try_get_tokenizer_config(
1724 - self.tokenizer,
1645 + tokenizer or self.model,
1646 trust_remote_code=self.trust_remote_code,
1726 - revision=self.tokenizer_revision,
1647 + revision=tokenizer_revision or self.revision,
1648 )
1728 - max_model_len = _get_and_verify_max_len(
1649 +
1650 + self.max_model_len = _get_and_verify_max_len(
1651 hf_config=self.hf_text_config,
1652 tokenizer_config=tokenizer_config,
1731 - max_model_len=max_model_len,
1653 + max_model_len=original_max_model_len,
1654 disable_sliding_window=self.disable_sliding_window,
1655 sliding_window=self.get_sliding_window(),
1656 spec_target_max_model_len=self.spec_target_max_model_len,
1657 encoder_config=self.encoder_config,
1658 )
1737 - logger.info("Using max model len %s", max_model_len)
1738 - return max_model_len
1659 + logger.info("Using max model len %s", self.max_model_len)
1660
1661 @property
1662 def attn_type(self) -> AttnTypeStr:
vllm/config/multimodal.py
-4
@@ -79,10 +79,6 @@ class MultiModalConfig:
79
80 WARNING: The vLLM engine may crash if incorrect shape of embeddings is passed.
81 Only enable this flag for trusted users!"""
82 - media_io_kwargs: dict[str, dict[str, Any]] = Field(default_factory=dict)
83 - """Additional args passed to process media inputs, keyed by modalities.
84 - For example, to set num_frames for video, set
85 - `--media-io-kwargs '{"video": {"num_frames": 40} }'`"""
82 mm_processor_kwargs: dict[str, object] | None = None
83 """Arguments to be forwarded to the model's processor for multi-modal data,
84 e.g., image processor. Overrides for the multi-modal processor obtained
vllm/config/renderer.py new
+109
@@ -0,0 +1,109 @@
1 +# SPDX-License-Identifier: Apache-2.0
2 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 +from typing import Any, Literal
4 +
5 +from pydantic import Field, SkipValidation
6 +from pydantic.dataclasses import dataclass
7 +
8 +from vllm.config.model import ModelConfig
9 +from vllm.config.utils import config
10 +from vllm.transformers_utils.gguf_utils import is_gguf
11 +from vllm.transformers_utils.runai_utils import ObjectStorageModel, is_runai_obj_uri
12 +from vllm.transformers_utils.utils import maybe_model_redirect
13 +
14 +TokenizerMode = Literal["auto", "hf", "slow", "mistral", "deepseek_v32"]
15 +
16 +
17 +@config
18 +@dataclass
19 +class RendererConfig:
20 + """Configuration for the renderer."""
21 +
22 + # NOTE: In reality, this is a required argument.
23 + # We provide a dummy default value here to generate the CLI args.
24 + model_config: SkipValidation[ModelConfig] = None # type: ignore
25 + """Provides model context to the renderer."""
26 +
27 + tokenizer: str = ""
28 + """Name or path of the Hugging Face tokenizer to use. If unspecified, model
29 + name or path will be used."""
30 + tokenizer_mode: TokenizerMode | str = "auto"
31 + """Tokenizer mode:\n
32 + - "auto" will use the tokenizer from `mistral_common` for Mistral models
33 + if available, otherwise it will use the "hf" tokenizer.\n
34 + - "hf" will use the fast tokenizer if available.\n
35 + - "slow" will always use the slow tokenizer.\n
36 + - "mistral" will always use the tokenizer from `mistral_common`.\n
37 + - "deepseek_v32" will always use the tokenizer from `deepseek_v32`.\n
38 + - Other custom values can be supported via plugins."""
39 + tokenizer_revision: str | None = None
40 + """The specific revision to use for the tokenizer on the Hugging Face Hub.
41 + It can be a branch name, a tag name, or a commit id. If unspecified, will
42 + use the default version."""
43 + skip_tokenizer_init: bool = False
44 + """Skip initialization of tokenizer and detokenizer. Expects valid
45 + `prompt_token_ids` and `None` for prompt from the input. The generated
46 + output will contain token ids."""
47 +
48 + io_processor_plugin: str | None = None
49 + """IOProcessor plugin name to load at model startup."""
50 +
51 + media_io_kwargs: dict[str, dict[str, Any]] = Field(default_factory=dict)
52 + """Additional args passed to process media inputs, keyed by modalities.
53 + For example, to set num_frames for video, set
54 + `--media-io-kwargs '{"video": {"num_frames": 40} }'`"""
55 + allowed_local_media_path: str = ""
56 + """Allowing API requests to read local images or videos from directories
57 + specified by the server file system. This is a security risk. Should only
58 + be enabled in trusted environments."""
59 + allowed_media_domains: list[str] | None = None
60 + """If set, only media URLs that belong to this domain can be used for
61 + multi-modal inputs. """
62 +
63 + @property
64 + def trust_remote_code(self) -> bool:
65 + return self.model_config.trust_remote_code
66 +
67 + def __post_init__(self) -> None:
68 + model_config = self.model_config
69 +
70 + # The tokenizer is consistent with the model by default.
71 + if not self.tokenizer:
72 + self.tokenizer = (
73 + ModelConfig.model
74 + if model_config is None
75 + else model_config.original_model
76 + )
77 + if not self.tokenizer_revision:
78 + self.tokenizer_revision = (
79 + ModelConfig.revision if model_config is None else model_config.revision
80 + )
81 +
82 + self.original_tokenizer = self.tokenizer
83 + self.tokenizer = maybe_model_redirect(self.original_tokenizer)
84 + self.maybe_pull_tokenizer_for_runai(self.tokenizer)
85 +
86 + # Multimodal GGUF models must use original repo for mm processing
87 + is_multimodal_model = (
88 + ModelConfig.is_multimodal_model
89 + if model_config is None
90 + else model_config.is_multimodal_model
91 + )
92 + if is_gguf(self.tokenizer) and is_multimodal_model:
93 + raise ValueError(
94 + "Loading a multimodal GGUF model needs to use original "
95 + "tokenizer. Please specify the unquantized hf model's "
96 + "repo name or path using the --tokenizer argument."
97 + )
98 +
99 + def maybe_pull_tokenizer_for_runai(self, tokenizer: str) -> None:
100 + """Pull tokenizer from Object Storage to temporary directory when needed."""
101 + if not is_runai_obj_uri(tokenizer):
102 + return
103 +
104 + object_storage_tokenizer = ObjectStorageModel(url=tokenizer)
105 + object_storage_tokenizer.pull_files(
106 + tokenizer,
107 + ignore_pattern=["*.pt", "*.safetensors", "*.bin", "*.tensors", "*.pth"],
108 + )
109 + self.tokenizer = object_storage_tokenizer.dir
vllm/config/speculative.py
-5
@@ -322,16 +322,11 @@ class SpeculativeConfig:
322 self.draft_model_config = ModelConfig(
323 model=self.model,
324 runner="draft",
325 - tokenizer=self.target_model_config.tokenizer,
326 - tokenizer_mode=self.target_model_config.tokenizer_mode,
325 trust_remote_code=self.target_model_config.trust_remote_code,
328 - allowed_local_media_path=self.target_model_config.allowed_local_media_path,
329 - allowed_media_domains=self.target_model_config.allowed_media_domains,
326 dtype=self.target_model_config.dtype,
327 seed=self.target_model_config.seed,
328 revision=self.revision,
329 code_revision=self.code_revision,
334 - tokenizer_revision=self.target_model_config.tokenizer_revision,
330 spec_target_max_model_len=self.target_model_config.max_model_len,
331 quantization=self.quantization,
332 enforce_eager=self.target_model_config.enforce_eager,
vllm/config/vllm.py
+15 -10
@@ -39,6 +39,7 @@ from .lora import LoRAConfig
39 from .model import ModelConfig
40 from .observability import ObservabilityConfig
41 from .parallel import ParallelConfig
42 +from .renderer import RendererConfig
43 from .scheduler import SchedulerConfig
44 from .speculative import SpeculativeConfig
45 from .structured_outputs import StructuredOutputsConfig
@@ -181,6 +182,8 @@ class VllmConfig:
182 # try to download a model
183 model_config: ModelConfig = Field(default=None)
184 """Model configuration."""
185 + renderer_config: RendererConfig = Field(default_factory=RendererConfig)
186 + """Renderer configuration."""
187 cache_config: CacheConfig = Field(default_factory=CacheConfig)
188 """Cache configuration."""
189 parallel_config: ParallelConfig = Field(default_factory=ParallelConfig)
@@ -741,7 +744,7 @@ class VllmConfig:
744 from vllm.multimodal import MULTIMODAL_REGISTRY
745
746 self.scheduler_config.max_num_encoder_input_tokens = (
744 - MULTIMODAL_REGISTRY.get_encdec_max_encoder_len(self.model_config)
747 + MULTIMODAL_REGISTRY.get_encdec_max_encoder_len(self.renderer_config)
748 )
749 logger.debug(
750 "Encoder-decoder model detected: setting "
@@ -1186,11 +1189,13 @@ class VllmConfig:
1189 computed_compile_ranges_split_points
1190 )
1191
1189 - def recalculate_max_model_len(self, max_model_len: int):
1190 - # Can only be called in try_verify_and_update_config
1191 - model_config = self.model_config
1192 - max_model_len = model_config.get_and_verify_max_len(max_model_len)
1193 - self.model_config.max_model_len = max_model_len
1192 + def recalculate_max_model_len(self, original_max_model_len: int | None) -> None:
1193 + # Can only be called during try_verify_and_update_config
1194 + self.model_config.recalculate_max_model_len(
1195 + original_max_model_len,
1196 + tokenizer=self.renderer_config.tokenizer,
1197 + tokenizer_revision=self.renderer_config.tokenizer_revision,
1198 + )
1199
1200 def try_verify_and_update_config(self):
1201 if self.model_config is None:
@@ -1264,11 +1269,11 @@ class VllmConfig:
1269 return (
1270 f"model={self.model_config.model!r}, "
1271 f"speculative_config={self.speculative_config!r}, "
1267 - f"tokenizer={self.model_config.tokenizer!r}, "
1268 - f"skip_tokenizer_init={self.model_config.skip_tokenizer_init}, "
1269 - f"tokenizer_mode={self.model_config.tokenizer_mode}, "
1272 + f"tokenizer={self.renderer_config.tokenizer!r}, "
1273 + f"skip_tokenizer_init={self.renderer_config.skip_tokenizer_init}, "
1274 + f"tokenizer_mode={self.renderer_config.tokenizer_mode}, "
1275 f"revision={self.model_config.revision}, "
1271 - f"tokenizer_revision={self.model_config.tokenizer_revision}, "
1276 + f"tokenizer_revision={self.renderer_config.tokenizer_revision}, "
1277 f"trust_remote_code={self.model_config.trust_remote_code}, "
1278 f"dtype={self.model_config.dtype}, "
1279 f"max_seq_len={self.model_config.max_model_len}, "
vllm/engine/arg_utils.py
+59 -40
@@ -71,11 +71,11 @@ from vllm.config.model import (
71 ModelDType,
72 RunnerOption,
73 TaskOption,
74 - TokenizerMode,
74 )
75 from vllm.config.multimodal import MMCacheType, MMEncoderTPMode
76 from vllm.config.observability import DetailedTraceModules
77 from vllm.config.parallel import DistributedExecutorBackend, ExpertPlacementStrategy
78 +from vllm.config.renderer import RendererConfig, TokenizerMode
79 from vllm.config.scheduler import SchedulerPolicy
80 from vllm.config.utils import get_field
81 from vllm.config.vllm import OptimizationLevel
@@ -355,17 +355,12 @@ class EngineArgs:
355
356 model: str = ModelConfig.model
357 served_model_name: str | list[str] | None = ModelConfig.served_model_name
358 - tokenizer: str | None = ModelConfig.tokenizer
358 hf_config_path: str | None = ModelConfig.hf_config_path
359 runner: RunnerOption = ModelConfig.runner
360 convert: ConvertOption = ModelConfig.convert
361 task: TaskOption | None = ModelConfig.task
363 - skip_tokenizer_init: bool = ModelConfig.skip_tokenizer_init
362 enable_prompt_embeds: bool = ModelConfig.enable_prompt_embeds
365 - tokenizer_mode: TokenizerMode | str = ModelConfig.tokenizer_mode
363 trust_remote_code: bool = ModelConfig.trust_remote_code
367 - allowed_local_media_path: str = ModelConfig.allowed_local_media_path
368 - allowed_media_domains: list[str] | None = ModelConfig.allowed_media_domains
364 download_dir: str | None = LoadConfig.download_dir
365 safetensors_load_strategy: str = LoadConfig.safetensors_load_strategy
366 load_format: str | LoadFormats = LoadConfig.load_format
@@ -449,7 +444,6 @@ class EngineArgs:
444 code_revision: str | None = ModelConfig.code_revision
445 hf_token: bool | str | None = ModelConfig.hf_token
446 hf_overrides: HfOverrides = get_field(ModelConfig, "hf_overrides")
452 - tokenizer_revision: str | None = ModelConfig.tokenizer_revision
447 quantization: QuantizationMethods | None = ModelConfig.quantization
448 enforce_eager: bool = ModelConfig.enforce_eager
449 disable_custom_all_reduce: bool = ParallelConfig.disable_custom_all_reduce
@@ -458,9 +452,6 @@ class EngineArgs:
452 )
453 enable_mm_embeds: bool = MultiModalConfig.enable_mm_embeds
454 interleave_mm_strings: bool = MultiModalConfig.interleave_mm_strings
461 - media_io_kwargs: dict[str, dict[str, Any]] = get_field(
462 - MultiModalConfig, "media_io_kwargs"
463 - )
455 mm_processor_kwargs: dict[str, Any] | None = MultiModalConfig.mm_processor_kwargs
456 disable_mm_preprocessor_cache: bool = False # DEPRECATED
457 mm_processor_cache_gb: float = MultiModalConfig.mm_processor_cache_gb
@@ -474,9 +465,19 @@ class EngineArgs:
465 mm_encoder_attn_backend: AttentionBackendEnum | str | None = (
466 MultiModalConfig.mm_encoder_attn_backend
467 )
477 - io_processor_plugin: str | None = None
468 skip_mm_profiling: bool = MultiModalConfig.skip_mm_profiling
469 video_pruning_rate: float = MultiModalConfig.video_pruning_rate
470 + # Renderer fields
471 + tokenizer: str | None = None
472 + tokenizer_mode: TokenizerMode | str = RendererConfig.tokenizer_mode
473 + tokenizer_revision: str | None = RendererConfig.tokenizer_revision
474 + skip_tokenizer_init: bool = RendererConfig.skip_tokenizer_init
475 + io_processor_plugin: str | None = None
476 + media_io_kwargs: dict[str, dict[str, Any]] = get_field(
477 + RendererConfig, "media_io_kwargs"
478 + )
479 + allowed_local_media_path: str = RendererConfig.allowed_local_media_path
480 + allowed_media_domains: list[str] | None = RendererConfig.allowed_media_domains
481 # LoRA fields
482 enable_lora: bool = False
483 max_loras: int = LoRAConfig.max_loras
@@ -627,25 +628,14 @@ class EngineArgs:
628 model_group.add_argument("--runner", **model_kwargs["runner"])
629 model_group.add_argument("--convert", **model_kwargs["convert"])
630 model_group.add_argument("--task", **model_kwargs["task"], deprecated=True)
630 - model_group.add_argument("--tokenizer", **model_kwargs["tokenizer"])
631 - model_group.add_argument("--tokenizer-mode", **model_kwargs["tokenizer_mode"])
631 model_group.add_argument(
632 "--trust-remote-code", **model_kwargs["trust_remote_code"]
633 )
634 model_group.add_argument("--dtype", **model_kwargs["dtype"])
635 model_group.add_argument("--seed", **model_kwargs["seed"])
636 model_group.add_argument("--hf-config-path", **model_kwargs["hf_config_path"])
638 - model_group.add_argument(
639 - "--allowed-local-media-path", **model_kwargs["allowed_local_media_path"]
640 - )
641 - model_group.add_argument(
642 - "--allowed-media-domains", **model_kwargs["allowed_media_domains"]
643 - )
637 model_group.add_argument("--revision", **model_kwargs["revision"])
638 model_group.add_argument("--code-revision", **model_kwargs["code_revision"])
646 - model_group.add_argument(
647 - "--tokenizer-revision", **model_kwargs["tokenizer_revision"]
648 - )
639 model_group.add_argument("--max-model-len", **model_kwargs["max_model_len"])
640 model_group.add_argument("--quantization", "-q", **model_kwargs["quantization"])
641 model_group.add_argument("--enforce-eager", **model_kwargs["enforce_eager"])
@@ -657,9 +647,6 @@ class EngineArgs:
647 model_group.add_argument(
648 "--disable-cascade-attn", **model_kwargs["disable_cascade_attn"]
649 )
660 - model_group.add_argument(
661 - "--skip-tokenizer-init", **model_kwargs["skip_tokenizer_init"]
662 - )
650 model_group.add_argument(
651 "--enable-prompt-embeds", **model_kwargs["enable_prompt_embeds"]
652 )
@@ -698,8 +685,34 @@ class EngineArgs:
685 model_group.add_argument(
686 "--logits-processors", **model_kwargs["logits_processors"]
687 )
701 - model_group.add_argument(
702 - "--io-processor-plugin", **model_kwargs["io_processor_plugin"]
688 +
689 + # Renderer arguments
690 + renderer_kwargs = get_kwargs(RendererConfig)
691 + renderer_group = parser.add_argument_group(
692 + title="RendererConfig",
693 + description=RendererConfig.__doc__,
694 + )
695 + renderer_group.add_argument("--tokenizer", **renderer_kwargs["tokenizer"])
696 + renderer_group.add_argument(
697 + "--tokenizer-mode", **renderer_kwargs["tokenizer_mode"]
698 + )
699 + renderer_group.add_argument(
700 + "--tokenizer-revision", **renderer_kwargs["tokenizer_revision"]
701 + )
702 + renderer_group.add_argument(
703 + "--skip-tokenizer-init", **renderer_kwargs["skip_tokenizer_init"]
704 + )
705 + renderer_group.add_argument(
706 + "--media-io-kwargs", **renderer_kwargs["media_io_kwargs"]
707 + )
708 + renderer_group.add_argument(
709 + "--allowed-local-media-path", **renderer_kwargs["allowed_local_media_path"]
710 + )
711 + renderer_group.add_argument(
712 + "--allowed-media-domains", **renderer_kwargs["allowed_media_domains"]
713 + )
714 + renderer_group.add_argument(
715 + "--io-processor-plugin", **renderer_kwargs["io_processor_plugin"]
716 )
717
718 # Model loading arguments
@@ -949,9 +962,6 @@ class EngineArgs:
962 multimodal_group.add_argument(
963 "--enable-mm-embeds", **multimodal_kwargs["enable_mm_embeds"]
964 )
952 - multimodal_group.add_argument(
953 - "--media-io-kwargs", **multimodal_kwargs["media_io_kwargs"]
954 - )
965 multimodal_group.add_argument(
966 "--mm-processor-kwargs", **multimodal_kwargs["mm_processor_kwargs"]
967 )
@@ -1255,18 +1265,13 @@ class EngineArgs:
1265 runner=self.runner,
1266 convert=self.convert,
1267 task=self.task,
1258 - tokenizer=self.tokenizer,
1259 - tokenizer_mode=self.tokenizer_mode,
1268 trust_remote_code=self.trust_remote_code,
1261 - allowed_local_media_path=self.allowed_local_media_path,
1262 - allowed_media_domains=self.allowed_media_domains,
1269 dtype=self.dtype,
1270 seed=self.seed,
1271 revision=self.revision,
1272 code_revision=self.code_revision,
1273 hf_token=self.hf_token,
1274 hf_overrides=self.hf_overrides,
1269 - tokenizer_revision=self.tokenizer_revision,
1275 max_model_len=self.max_model_len,
1276 quantization=self.quantization,
1277 enforce_eager=self.enforce_eager,
@@ -1274,13 +1279,11 @@ class EngineArgs:
1279 logprobs_mode=self.logprobs_mode,
1280 disable_sliding_window=self.disable_sliding_window,
1281 disable_cascade_attn=self.disable_cascade_attn,
1277 - skip_tokenizer_init=self.skip_tokenizer_init,
1282 enable_prompt_embeds=self.enable_prompt_embeds,
1283 served_model_name=self.served_model_name,
1284 limit_mm_per_prompt=self.limit_mm_per_prompt,
1285 enable_mm_embeds=self.enable_mm_embeds,
1286 interleave_mm_strings=self.interleave_mm_strings,
1283 - media_io_kwargs=self.media_io_kwargs,
1287 skip_mm_profiling=self.skip_mm_profiling,
1288 config_format=self.config_format,
1289 mm_processor_kwargs=self.mm_processor_kwargs,
@@ -1298,7 +1301,6 @@ class EngineArgs:
1301 override_attention_dtype=self.override_attention_dtype,
1302 logits_processors=self.logits_processors,
1303 video_pruning_rate=self.video_pruning_rate,
1301 - io_processor_plugin=self.io_processor_plugin,
1304 )
1305
1306 def validate_tensorizer_args(self):
@@ -1394,9 +1396,25 @@ class EngineArgs:
1396 )
1397
1398 model_config = self.create_model_config()
1397 - self.model = model_config.model
1398 - self.tokenizer = model_config.tokenizer
1399 + renderer_config = RendererConfig(
1400 + model_config=model_config,
1401 + tokenizer=self.tokenizer or "",
1402 + tokenizer_mode=self.tokenizer_mode,
1403 + tokenizer_revision=self.tokenizer_revision,
1404 + skip_tokenizer_init=self.skip_tokenizer_init,
1405 + io_processor_plugin=self.io_processor_plugin,
1406 + media_io_kwargs=self.media_io_kwargs,
1407 + allowed_local_media_path=self.allowed_local_media_path,
1408 + allowed_media_domains=self.allowed_media_domains,
1409 + )
1410
1411 + model_config.recalculate_max_model_len(
1412 + model_config.original_max_model_len,
1413 + tokenizer=renderer_config.tokenizer,
1414 + tokenizer_revision=renderer_config.tokenizer_revision,
1415 + )
1416 +
1417 + self.model = model_config.model
1418 self._check_feature_supported(model_config)
1419 self._set_default_chunked_prefill_and_prefix_caching_args(model_config)
1420 self._set_default_max_num_seqs_and_batched_tokens_args(
@@ -1768,6 +1786,7 @@ class EngineArgs:
1786 )
1787 config = VllmConfig(
1788 model_config=model_config,
1789 + renderer_config=renderer_config,
1790 cache_config=cache_config,
1791 parallel_config=parallel_config,
1792 scheduler_config=scheduler_config,
vllm/engine/protocol.py
+2 -1
@@ -5,7 +5,7 @@ from abc import ABC, abstractmethod
5 from collections.abc import AsyncGenerator, Iterable, Mapping
6 from typing import Any
7
8 -from vllm.config import ModelConfig, VllmConfig
8 +from vllm.config import ModelConfig, RendererConfig, VllmConfig
9 from vllm.inputs.data import PromptType
10 from vllm.lora.request import LoRARequest
11 from vllm.outputs import PoolingRequestOutput, RequestOutput
@@ -22,6 +22,7 @@ class EngineClient(ABC):
22 """Protocol class for Clients to Engine"""
23
24 vllm_config: VllmConfig
25 + renderer_config: RendererConfig
26 model_config: ModelConfig
27 input_processor: InputProcessor
28 io_processor: IOProcessor | None
vllm/entrypoints/chat_utils.py
+45 -34
@@ -44,7 +44,7 @@ from transformers import PreTrainedTokenizer, PreTrainedTokenizerFast, Processor
44 from typing_extensions import Required, TypedDict
45
46 from vllm import envs
47 -from vllm.config import ModelConfig
47 +from vllm.config import ModelConfig, RendererConfig
48 from vllm.logger import init_logger
49 from vllm.model_executor.models import SupportsMultiModal
50 from vllm.multimodal import MULTIMODAL_REGISTRY, MultiModalDataDict, MultiModalUUIDDict
@@ -452,9 +452,10 @@ This is needed because `lru_cache` does not cache when an exception happens.
452
453 def _try_get_processor_chat_template(
454 tokenizer: PreTrainedTokenizer | PreTrainedTokenizerFast,
455 - model_config: ModelConfig,
455 + *,
456 + trust_remote_code: bool,
457 ) -> str | None:
457 - cache_key = (tokenizer.name_or_path, model_config.trust_remote_code)
458 + cache_key = (tokenizer.name_or_path, trust_remote_code)
459 if cache_key in _PROCESSOR_CHAT_TEMPLATES:
460 return _PROCESSOR_CHAT_TEMPLATES[cache_key]
461
@@ -466,7 +467,7 @@ def _try_get_processor_chat_template(
467 PreTrainedTokenizerFast,
468 ProcessorMixin,
469 ),
469 - trust_remote_code=model_config.trust_remote_code,
470 + trust_remote_code=trust_remote_code,
471 )
472 if (
473 isinstance(processor, ProcessorMixin)
@@ -499,7 +500,10 @@ def resolve_hf_chat_template(
500
501 # 2nd priority: AutoProcessor chat template, unless tool calling is enabled
502 if tools is None:
502 - chat_template = _try_get_processor_chat_template(tokenizer, model_config)
503 + chat_template = _try_get_processor_chat_template(
504 + tokenizer,
505 + trust_remote_code=model_config.trust_remote_code,
506 + )
507 if chat_template is not None:
508 return chat_template
509
@@ -513,10 +517,10 @@ def resolve_hf_chat_template(
517 exc_info=True,
518 )
519
516 - # 4th priority: Predefined fallbacks
520 + # 4th priority: Predefined fallbacks]
521 path = get_chat_template_fallback_path(
522 model_type=model_config.hf_config.model_type,
519 - tokenizer_name_or_path=model_config.tokenizer,
523 + tokenizer_name_or_path=tokenizer.name_or_path,
524 )
525 if path is not None:
526 logger.info_once(
@@ -538,14 +542,14 @@ def _resolve_chat_template_content_format(
542 tools: list[dict[str, Any]] | None,
543 tokenizer: TokenizerLike | None,
544 *,
541 - model_config: ModelConfig,
545 + renderer_config: RendererConfig,
546 ) -> _ChatTemplateContentFormat:
547 if isinstance(tokenizer, (PreTrainedTokenizer, PreTrainedTokenizerFast)):
548 hf_chat_template = resolve_hf_chat_template(
549 tokenizer,
550 chat_template=chat_template,
551 tools=tools,
548 - model_config=model_config,
552 + model_config=renderer_config.model_config,
553 )
554 else:
555 hf_chat_template = None
@@ -595,7 +599,7 @@ def resolve_chat_template_content_format(
599 given_format: ChatTemplateContentFormatOption,
600 tokenizer: TokenizerLike | None,
601 *,
598 - model_config: ModelConfig,
602 + renderer_config: RendererConfig,
603 ) -> _ChatTemplateContentFormat:
604 if given_format != "auto":
605 return given_format
@@ -604,7 +608,7 @@ def resolve_chat_template_content_format(
608 chat_template,
609 tools,
610 tokenizer,
607 - model_config=model_config,
611 + renderer_config=renderer_config,
612 )
613
614 _log_chat_template_content_format(
@@ -627,32 +631,32 @@ class BaseMultiModalItemTracker(ABC, Generic[_T]):
631 maximum per prompt.
632 """
633
630 - def __init__(self, model_config: ModelConfig):
634 + def __init__(self, renderer_config: RendererConfig):
635 super().__init__()
636
633 - self._model_config = model_config
637 + self._renderer_config = renderer_config
638
639 self._items_by_modality = defaultdict[str, list[_T | None]](list)
640 self._uuids_by_modality = defaultdict[str, list[str | None]](list)
641
642 @property
639 - def model_config(self) -> ModelConfig:
640 - return self._model_config
643 + def renderer_config(self) -> RendererConfig:
644 + return self._renderer_config
645
646 @cached_property
647 def model_cls(self) -> type[SupportsMultiModal]:
648 from vllm.model_executor.model_loader import get_model_cls
649
646 - model_cls = get_model_cls(self.model_config)
650 + model_cls = get_model_cls(self.renderer_config.model_config)
651 return cast(type[SupportsMultiModal], model_cls)
652
653 @property
654 def allowed_local_media_path(self):
651 - return self._model_config.allowed_local_media_path
655 + return self._renderer_config.allowed_local_media_path
656
657 @property
658 def allowed_media_domains(self):
655 - return self._model_config.allowed_media_domains
659 + return self._renderer_config.allowed_media_domains
660
661 @property
662 def mm_registry(self):
@@ -660,7 +664,7 @@ class BaseMultiModalItemTracker(ABC, Generic[_T]):
664
665 @cached_property
666 def mm_processor(self):
663 - return self.mm_registry.create_processor(self.model_config)
667 + return self.mm_registry.create_processor(self.renderer_config)
668
669 def add(
670 self,
@@ -851,19 +855,20 @@ class MultiModalContentParser(BaseMultiModalContentParser):
855 super().__init__()
856
857 self._tracker = tracker
854 - multimodal_config = self._tracker.model_config.multimodal_config
855 - media_io_kwargs = getattr(multimodal_config, "media_io_kwargs", None)
856 -
858 self._connector: MediaConnector = MEDIA_CONNECTOR_REGISTRY.load(
859 envs.VLLM_MEDIA_CONNECTOR,
859 - media_io_kwargs=media_io_kwargs,
860 + media_io_kwargs=self.renderer_config.media_io_kwargs,
861 allowed_local_media_path=tracker.allowed_local_media_path,
862 allowed_media_domains=tracker.allowed_media_domains,
863 )
864
865 + @property
866 + def renderer_config(self) -> RendererConfig:
867 + return self._tracker.renderer_config
868 +
869 @property
870 def model_config(self) -> ModelConfig:
866 - return self._tracker.model_config
871 + return self.renderer_config.model_config
872
873 def parse_image(self, image_url: str | None, uuid: str | None = None) -> None:
874 image = self._connector.fetch_image(image_url) if image_url else None
@@ -963,18 +968,20 @@ class AsyncMultiModalContentParser(BaseMultiModalContentParser):
968 super().__init__()
969
970 self._tracker = tracker
966 - multimodal_config = self._tracker.model_config.multimodal_config
967 - media_io_kwargs = getattr(multimodal_config, "media_io_kwargs", None)
971 self._connector: MediaConnector = MEDIA_CONNECTOR_REGISTRY.load(
972 envs.VLLM_MEDIA_CONNECTOR,
970 - media_io_kwargs=media_io_kwargs,
973 + media_io_kwargs=self.renderer_config.media_io_kwargs,
974 allowed_local_media_path=tracker.allowed_local_media_path,
975 allowed_media_domains=tracker.allowed_media_domains,
976 )
977
978 + @property
979 + def renderer_config(self) -> RendererConfig:
980 + return self._tracker.renderer_config
981 +
982 @property
983 def model_config(self) -> ModelConfig:
977 - return self._tracker.model_config
984 + return self.renderer_config.model_config
985
986 def parse_image(self, image_url: str | None, uuid: str | None = None) -> None:
987 image_coro = self._connector.fetch_image_async(image_url) if image_url else None
@@ -1604,15 +1611,17 @@ def _postprocess_messages(messages: list[ConversationMessage]) -> None:
1611
1612 def parse_chat_messages(
1613 messages: list[ChatCompletionMessageParam],
1607 - model_config: ModelConfig,
1614 + renderer_config: RendererConfig,
1615 content_format: _ChatTemplateContentFormat,
1616 ) -> tuple[
1617 list[ConversationMessage],
1618 MultiModalDataDict | None,
1619 MultiModalUUIDDict | None,
1620 ]:
1621 + model_config = renderer_config.model_config
1622 +
1623 conversation: list[ConversationMessage] = []
1615 - mm_tracker = MultiModalItemTracker(model_config)
1624 + mm_tracker = MultiModalItemTracker(renderer_config)
1625
1626 for msg in messages:
1627 sub_messages = _parse_chat_message_content(
@@ -1635,15 +1644,17 @@ def parse_chat_messages(
1644
1645 def parse_chat_messages_futures(
1646 messages: list[ChatCompletionMessageParam],
1638 - model_config: ModelConfig,
1647 + renderer_config: RendererConfig,
1648 content_format: _ChatTemplateContentFormat,
1649 ) -> tuple[
1650 list[ConversationMessage],
1651 Awaitable[MultiModalDataDict | None],
1652 MultiModalUUIDDict | None,
1653 ]:
1654 + model_config = renderer_config.model_config
1655 +
1656 conversation: list[ConversationMessage] = []
1646 - mm_tracker = AsyncMultiModalItemTracker(model_config)
1657 + mm_tracker = AsyncMultiModalItemTracker(renderer_config)
1658
1659 for msg in messages:
1660 sub_messages = _parse_chat_message_content(
@@ -1748,14 +1759,14 @@ def apply_hf_chat_template(
1759 chat_template: str | None,
1760 tools: list[dict[str, Any]] | None,
1761 *,
1751 - model_config: ModelConfig,
1762 + renderer_config: RendererConfig,
1763 **kwargs: Any,
1764 ) -> str:
1765 hf_chat_template = resolve_hf_chat_template(
1766 tokenizer,
1767 chat_template=chat_template,
1768 tools=tools,
1758 - model_config=model_config,
1769 + model_config=renderer_config.model_config,
1770 )
1771
1772 if hf_chat_template is None:
vllm/entrypoints/llm.py
+8 -6
@@ -29,8 +29,8 @@ from vllm.config.model import (
29 HfOverrides,
30 ModelDType,
31 RunnerOption,
32 - TokenizerMode,
32 )
33 +from vllm.config.renderer import TokenizerMode
34 from vllm.engine.arg_utils import EngineArgs
35 from vllm.entrypoints.chat_utils import (
36 ChatCompletionMessageParam,
@@ -343,6 +343,7 @@ class LLM:
343 logger.info("Supported tasks: %s", supported_tasks)
344 self.supported_tasks = supported_tasks
345
346 + self.renderer_config = self.llm_engine.renderer_config
347 self.model_config = self.llm_engine.model_config
348 self.input_processor = self.llm_engine.input_processor
349 self.io_processor = self.llm_engine.io_processor
@@ -808,13 +809,13 @@ class LLM:
809 list_of_messages = [cast(list[ChatCompletionMessageParam], messages)]
810
811 tokenizer = self.get_tokenizer()
811 - model_config = self.model_config
812 + renderer_config = self.renderer_config
813 resolved_content_format = resolve_chat_template_content_format(
814 chat_template,
815 tools,
816 chat_template_content_format,
817 tokenizer,
817 - model_config=model_config,
818 + renderer_config=renderer_config,
819 )
820
821 _chat_template_kwargs: dict[str, Any] = dict(
@@ -833,7 +834,7 @@ class LLM:
834 # the chat message parsing for it.
835 conversation, mm_data, mm_uuids = parse_chat_messages(
836 msgs,
836 - model_config,
837 + renderer_config,
838 content_format=resolved_content_format,
839 )
840
@@ -847,7 +848,7 @@ class LLM:
848 prompt_str = apply_hf_chat_template(
849 tokenizer=tokenizer,
850 conversation=conversation,
850 - model_config=model_config,
851 + renderer_config=renderer_config,
852 **_chat_template_kwargs,
853 )
854 # Special tokens are already included in chat templates so
@@ -1290,6 +1291,7 @@ class LLM:
1291 lora_request: list[LoRARequest] | LoRARequest | None = None,
1292 tokenization_kwargs: dict[str, Any] | None = None,
1293 ) -> list[ScoringRequestOutput]:
1294 + renderer_config = self.renderer_config
1295 model_config = self.model_config
1296
1297 if isinstance(tokenizer, MistralTokenizer):
@@ -1317,7 +1319,7 @@ class LLM:
1319
1320 for q, d in input_pairs:
1321 _, engine_prompt = get_score_prompt(
1320 - model_config=model_config,
1322 + renderer_config=renderer_config,
1323 data_1=q,
1324 data_2=d,
1325 tokenizer=tokenizer,
vllm/entrypoints/openai/api_server.py
+1 -1
@@ -1099,7 +1099,7 @@ async def init_app_state(
1099 logger.info("Supported tasks: %s", supported_tasks)
1100
1101 resolved_chat_template = await process_chat_template(
1102 - args.chat_template, engine_client, vllm_config.model_config
1102 + args.chat_template, engine_client, vllm_config.renderer_config
1103 )
1104
1105 if args.tool_server == "demo":
vllm/entrypoints/openai/serving_completion.py
+1 -1
@@ -122,7 +122,7 @@ class OpenAIServingCompletion(OpenAIServing):
122 try:
123 lora_request = self._maybe_get_adapters(request)
124
125 - if self.model_config.skip_tokenizer_init:
125 + if self.renderer_config.skip_tokenizer_init:
126 tokenizer = None
127 else:
128 tokenizer = await self.engine_client.get_tokenizer()
vllm/entrypoints/openai/serving_engine.py
+6 -5
@@ -291,6 +291,7 @@ class OpenAIServing:
291
292 self.input_processor = self.models.input_processor
293 self.io_processor = self.models.io_processor
294 + self.renderer_config = self.models.renderer_config
295 self.model_config = self.models.model_config
296 self.max_model_len = self.model_config.max_model_len
297
@@ -1100,18 +1101,18 @@ class OpenAIServing:
1101 Sequence[RequestPrompt],
1102 list[EngineTokensPrompt],
1103 ]:
1103 - model_config = self.model_config
1104 + renderer_config = self.renderer_config
1105
1106 resolved_content_format = resolve_chat_template_content_format(
1107 chat_template,
1108 tool_dicts,
1109 chat_template_content_format,
1110 tokenizer,
1110 - model_config=model_config,
1111 + renderer_config=renderer_config,
1112 )
1113 conversation, mm_data_future, mm_uuids = parse_chat_messages_futures(
1114 messages,
1114 - model_config,
1115 + renderer_config,
1116 content_format=resolved_content_format,
1117 )
1118
@@ -1138,14 +1139,14 @@ class OpenAIServing:
1139 request_prompt = tokenizer.apply_chat_template(
1140 conversation=conversation,
1141 messages=messages,
1141 - model_config=model_config,
1142 + model_config=renderer_config.model_config,
1143 **_chat_template_kwargs,
1144 )
1145 else:
1146 request_prompt = apply_hf_chat_template(
1147 tokenizer=tokenizer,
1148 conversation=conversation,
1148 - model_config=model_config,
1149 + renderer_config=renderer_config,
1150 **_chat_template_kwargs,
1151 )
1152
vllm/entrypoints/openai/serving_models.py
+1
@@ -71,6 +71,7 @@ class OpenAIServingModels:
71
72 self.input_processor = self.engine_client.input_processor
73 self.io_processor = self.engine_client.io_processor
74 + self.renderer_config = self.engine_client.renderer_config
75 self.model_config = self.engine_client.model_config
76 self.max_model_len = self.model_config.max_model_len
77
vllm/entrypoints/openai/speech_to_text.py
+5 -5
@@ -91,7 +91,7 @@ class OpenAISpeechToText(OpenAIServing):
91 self.task_type = task_type
92
93 self.asr_config = self.model_cls.get_speech_to_text_config(
94 - self.model_config, task_type
94 + self.renderer_config, task_type
95 )
96
97 self.enable_force_include_usage = enable_force_include_usage
@@ -101,8 +101,8 @@ class OpenAISpeechToText(OpenAIServing):
101 self.tokenizer = cast(
102 PreTrainedTokenizerBase,
103 get_tokenizer(
104 - tokenizer_name=self.model_config.tokenizer,
105 - tokenizer_mode=self.model_config.tokenizer_mode,
104 + tokenizer_name=self.renderer_config.tokenizer,
105 + tokenizer_mode=self.renderer_config.tokenizer_mode,
106 ),
107 )
108
@@ -154,7 +154,7 @@ class OpenAISpeechToText(OpenAIServing):
154 prompt = self.model_cls.get_generation_prompt(
155 audio=chunk,
156 stt_config=self.asr_config,
157 - model_config=self.model_config,
157 + renderer_config=self.renderer_config,
158 language=language,
159 task_type=self.task_type,
160 request_prompt=request.prompt,
@@ -428,7 +428,7 @@ class OpenAISpeechToText(OpenAIServing):
428 if res.prompt_token_ids is not None:
429 num_prompt_tokens = len(res.prompt_token_ids)
430 if audio_tokens := self.model_cls.get_num_audio_tokens(
431 - audio_duration_s, self.asr_config, self.model_config
431 + audio_duration_s, self.asr_config, self.renderer_config
432 ):
433 num_prompt_tokens += audio_tokens
434
vllm/entrypoints/pooling/pooling/serving.py
+1 -1
@@ -94,7 +94,7 @@ class OpenAIServingPooling(OpenAIServing):
94 try:
95 lora_request = self._maybe_get_adapters(request)
96
97 - if self.model_config.skip_tokenizer_init:
97 + if self.renderer_config.skip_tokenizer_init:
98 tokenizer = None
99 else:
100 tokenizer = await self.engine_client.get_tokenizer()
vllm/entrypoints/pooling/score/serving.py
+1 -3
@@ -160,10 +160,8 @@ class ServingScores(OpenAIServing):
160 data_1: str | ScoreContentPartParam,
161 data_2: str | ScoreContentPartParam,
162 ) -> tuple[str, TokensPrompt]:
163 - model_config = self.model_config
164 -
163 full_prompt, engine_prompt = get_score_prompt(
166 - model_config=model_config,
164 + renderer_config=self.renderer_config,
165 data_1=data_1,
166 data_2=data_2,
167 tokenizer=tokenizer,
vllm/entrypoints/score_utils.py
+8 -5
@@ -5,7 +5,7 @@ from typing import Any, TypeAlias, cast
5 from torch.nn import CosineSimilarity
6 from typing_extensions import Required, TypedDict
7
8 -from vllm.config import ModelConfig
8 +from vllm.config import ModelConfig, RendererConfig
9 from vllm.entrypoints.chat_utils import (
10 BaseMultiModalItemTracker,
11 ChatCompletionContentPartImageEmbedsParam,
@@ -88,9 +88,9 @@ def _validate_score_input_lens(
88 def parse_score_data(
89 data_1: str | ScoreContentPartParam,
90 data_2: str | ScoreContentPartParam,
91 - model_config: ModelConfig,
91 + renderer_config: RendererConfig,
92 ) -> tuple[str, str, MultiModalDataDict | None]:
93 - mm_tracker = MultiModalItemTracker(model_config)
93 + mm_tracker = MultiModalItemTracker(renderer_config)
94
95 content_1 = _parse_score_content(data_1, mm_tracker)
96 content_2 = _parse_score_content(data_2, mm_tracker)
@@ -176,7 +176,7 @@ def post_process_tokens(
176
177
178 def get_score_prompt(
179 - model_config: ModelConfig,
179 + renderer_config: RendererConfig,
180 tokenizer: TokenizerLike,
181 tokenization_kwargs: dict[str, Any],
182 data_1: str | ScoreContentPartParam,
@@ -185,11 +185,14 @@ def get_score_prompt(
185 prompt_1, prompt_2, mm_data = parse_score_data(
186 data_1,
187 data_2,
188 - model_config,
188 + renderer_config,
189 )
190 +
191 from vllm.model_executor.model_loader import get_model_cls
192
193 + model_config = renderer_config.model_config
194 model = get_model_cls(model_config)
195 +
196 if supports_score_template(model):
197 full_prompt = apply_score_template(model_config, prompt_1, prompt_2)
198 prompt_inputs = tokenizer(full_prompt, **tokenization_kwargs)
vllm/entrypoints/utils.py
+4 -4
@@ -13,7 +13,7 @@ from fastapi import Request
13 from fastapi.responses import JSONResponse, StreamingResponse
14 from starlette.background import BackgroundTask, BackgroundTasks
15
16 -from vllm.config import ModelConfig
16 +from vllm.config import RendererConfig
17 from vllm.engine.arg_utils import EngineArgs
18 from vllm.engine.protocol import EngineClient
19 from vllm.entrypoints.chat_utils import (
@@ -288,7 +288,7 @@ def process_lora_modules(
288 async def process_chat_template(
289 args_chat_template: Path | str | None,
290 engine_client: EngineClient,
291 - model_config: ModelConfig,
291 + renderer_config: RendererConfig,
292 ) -> str | None:
293 resolved_chat_template = load_chat_template(args_chat_template)
294 if resolved_chat_template is not None:
@@ -305,7 +305,7 @@ async def process_chat_template(
305 tokenizer=tokenizer,
306 chat_template=None,
307 tools=None,
308 - model_config=model_config,
308 + model_config=renderer_config.model_config,
309 )
310
311 if hf_chat_template != resolved_chat_template:
@@ -314,6 +314,6 @@ async def process_chat_template(
314 "It is different from official chat template '%s'. "
315 "This discrepancy may lead to performance degradation.",
316 resolved_chat_template,
317 - model_config.model,
317 + renderer_config.model_config.model,
318 )
319 return resolved_chat_template
vllm/inputs/preprocess.py
+5 -4
@@ -6,7 +6,7 @@ from typing import Any, cast
6
7 from typing_extensions import assert_never
8
9 -from vllm.config import ModelConfig
9 +from vllm.config import RendererConfig
10 from vllm.logger import init_logger
11 from vllm.multimodal import MULTIMODAL_REGISTRY, MultiModalRegistry
12 from vllm.multimodal.cache import BaseMultiModalProcessorCache
@@ -45,14 +45,15 @@ logger = init_logger(__name__)
45 class InputPreprocessor:
46 def __init__(
47 self,
48 - model_config: ModelConfig,
48 + renderer_config: RendererConfig,
49 tokenizer: TokenizerLike | None,
50 mm_registry: MultiModalRegistry = MULTIMODAL_REGISTRY,
51 mm_processor_cache: BaseMultiModalProcessorCache | None = None,
52 ) -> None:
53 super().__init__()
54
55 - self.model_config = model_config
55 + self.renderer_config = renderer_config
56 + self.model_config = renderer_config.model_config
57 self.tokenizer = tokenizer
58 self.mm_registry = mm_registry
59 self.mm_processor_cache = mm_processor_cache
@@ -231,7 +232,7 @@ class InputPreprocessor:
232 def _get_mm_processor(self) -> BaseMultiModalProcessor:
233 if not hasattr(self, "_mm_processor"):
234 self._mm_processor = self.mm_registry.create_processor(
234 - self.model_config,
235 + self.renderer_config,
236 tokenizer=self.tokenizer,
237 cache=self.mm_processor_cache,
238 )
vllm/model_executor/models/adapters.py
+10 -10
@@ -415,7 +415,7 @@ def load_weights_using_from_2_way_softmax(
415 from vllm.model_executor.layers.vocab_parallel_embedding import ParallelLMHead
416 from vllm.model_executor.model_loader.weight_utils import default_weight_loader
417
418 - model_config = model.vllm_config.model_config
418 + renderer_config = model.vllm_config.renderer_config
419 quant_config = model.vllm_config.quant_config
420 text_config = model.config.get_text_config()
421
@@ -447,10 +447,10 @@ def load_weights_using_from_2_way_softmax(
447 from vllm.tokenizers import get_tokenizer
448
449 tokenizer = get_tokenizer(
450 - model_config.tokenizer,
451 - revision=model_config.tokenizer_revision,
452 - tokenizer_mode=model_config.tokenizer_mode,
453 - trust_remote_code=model_config.trust_remote_code,
450 + renderer_config.tokenizer,
451 + revision=renderer_config.tokenizer_revision,
452 + tokenizer_mode=renderer_config.tokenizer_mode,
453 + trust_remote_code=renderer_config.trust_remote_code,
454 )
455
456 false_id = tokenizer.convert_tokens_to_ids(tokens[0])
@@ -473,7 +473,7 @@ def load_weights_no_post_processing(model, weights: Iterable[tuple[str, torch.Te
473 from vllm.model_executor.layers.vocab_parallel_embedding import ParallelLMHead
474 from vllm.model_executor.model_loader.weight_utils import default_weight_loader
475
476 - model_config = model.vllm_config.model_config
476 + renderer_config = model.vllm_config.renderer_config
477 quant_config = model.vllm_config.quant_config
478 text_config = model.config.get_text_config()
479
@@ -501,10 +501,10 @@ def load_weights_no_post_processing(model, weights: Iterable[tuple[str, torch.Te
501 from vllm.tokenizers import get_tokenizer
502
503 tokenizer = get_tokenizer(
504 - model_config.tokenizer,
505 - revision=model_config.tokenizer_revision,
506 - tokenizer_mode=model_config.tokenizer_mode,
507 - trust_remote_code=model_config.trust_remote_code,
504 + renderer_config.tokenizer,
505 + revision=renderer_config.tokenizer_revision,
506 + tokenizer_mode=renderer_config.tokenizer_mode,
507 + trust_remote_code=renderer_config.trust_remote_code,
508 )
509
510 token_ids = [tokenizer.convert_tokens_to_ids(t) for t in tokens]
vllm/model_executor/models/deepseek_ocr.py
+2 -2
@@ -377,8 +377,8 @@ class DeepseekOCRForCausalLM(nn.Module, SupportsMultiModal, SupportsPP):
377 self.projector_config = config.projector_config
378 self.text_config = config.text_config
379
380 - model_config = vllm_config.model_config
381 - tokenizer = cached_tokenizer_from_config(model_config)
380 + renderer_config = vllm_config.renderer_config
381 + tokenizer = cached_tokenizer_from_config(renderer_config)
382 self.image_token_id = tokenizer.vocab[_IMAGE_TOKEN]
383
384 self.sam_model = build_sam_vit_b()
vllm/model_executor/models/deepseek_vl2.py
+2 -2
@@ -370,8 +370,8 @@ class DeepseekVLV2ForCausalLM(nn.Module, SupportsMultiModal, SupportsPP):
370 self.projector_config = config.projector_config
371 self.text_config = config.text_config
372
373 - model_config = vllm_config.model_config
374 - tokenizer = cached_tokenizer_from_config(model_config)
373 + renderer_config = vllm_config.renderer_config
374 + tokenizer = cached_tokenizer_from_config(renderer_config)
375 self.image_token_id: int = tokenizer.vocab[_IMAGE_TOKEN]
376
377 self.vision = self._init_vision_module(
vllm/model_executor/models/gemma3n_mm.py
+5 -3
@@ -18,7 +18,7 @@ from transformers.models.gemma3n import (
18 )
19 from transformers.models.siglip import SiglipImageProcessorFast
20
21 -from vllm.config import ModelConfig, SpeechToTextConfig, VllmConfig
21 +from vllm.config import RendererConfig, SpeechToTextConfig, VllmConfig
22 from vllm.config.multimodal import BaseDummyOptions
23 from vllm.inputs.data import PromptType
24 from vllm.logger import init_logger
@@ -760,7 +760,7 @@ class Gemma3nForConditionalGeneration(
760 cls,
761 audio: np.ndarray,
762 stt_config: SpeechToTextConfig,
763 - model_config: ModelConfig,
763 + renderer_config: RendererConfig,
764 language: Optional[str],
765 task_type: Literal["transcribe", "translate"],
766 request_prompt: str,
@@ -798,7 +798,9 @@ class Gemma3nForConditionalGeneration(
798
799 @classmethod
800 def get_speech_to_text_config(
801 - cls, model_config: ModelConfig, task_type: str
801 + cls,
802 + renderer_config: RendererConfig,
803 + task_type: str,
804 ) -> SpeechToTextConfig:
805 return SpeechToTextConfig(
806 # Let's set this to 30 as suggested in the docs for now, although
vllm/model_executor/models/granite_speech.py
+8 -6
@@ -34,7 +34,7 @@ import torch.nn.functional as F
34 from torch import nn
35 from transformers import BatchFeature, PretrainedConfig
36
37 -from vllm.config import CacheConfig, ModelConfig, SpeechToTextConfig, VllmConfig
37 +from vllm.config import CacheConfig, RendererConfig, SpeechToTextConfig, VllmConfig
38 from vllm.config.multimodal import BaseDummyOptions
39 from vllm.inputs.data import PromptType
40 from vllm.model_executor.layers.linear import ColumnParallelLinear, RowParallelLinear
@@ -840,7 +840,7 @@ class GraniteSpeechForConditionalGeneration(
840 def get_generation_prompt(
841 cls,
842 audio: np.ndarray,
843 - model_config: ModelConfig,
843 + renderer_config: RendererConfig,
844 stt_config: SpeechToTextConfig,
845 language: str | None,
846 task_type: Literal["transcribe", "translate"],
@@ -861,7 +861,7 @@ class GraniteSpeechForConditionalGeneration(
861 else:
862 raise ValueError(f"Unsupported task type {task_type}")
863
864 - tokenizer = cached_tokenizer_from_config(model_config)
864 + tokenizer = cached_tokenizer_from_config(renderer_config)
865 chat = [dict(role="user", content=user_prompt)]
866 prompt = tokenizer.apply_chat_template(
867 chat,
@@ -882,10 +882,10 @@ class GraniteSpeechForConditionalGeneration(
882 cls,
883 audio_duration_s: float,
884 stt_config: SpeechToTextConfig,
885 - model_config: ModelConfig,
885 + renderer_config: RendererConfig,
886 ) -> int | None:
887 """Get the number of audio tokens for an audio duration in sec."""
888 - processor = cached_processor_from_config(model_config)
888 + processor = cached_processor_from_config(renderer_config)
889 hop_length = processor.audio_processor.melspec_kwargs["hop_length"]
890 proj_win_size = processor.audio_processor.projector_window_size
891 ds_rate = processor.audio_processor.projector_downsample_rate
@@ -903,7 +903,9 @@ class GraniteSpeechForConditionalGeneration(
903
904 @classmethod
905 def get_speech_to_text_config(
906 - cls, model_config: ModelConfig, task_type: str
906 + cls,
907 + renderer_config: RendererConfig,
908 + task_type: str,
909 ) -> SpeechToTextConfig:
910 """Get the stt config for this model."""
911 # Default settings are reasonable for this model and we don't currently
vllm/model_executor/models/gritlm.py
+7 -7
@@ -6,7 +6,7 @@ import numpy as np
6 import torch
7 import torch.nn as nn
8
9 -from vllm.config import ModelConfig, VllmConfig
9 +from vllm.config import RendererConfig, VllmConfig
10 from vllm.logger import init_logger
11 from vllm.model_executor.layers.pooler import (
12 DispatchPooler,
@@ -29,12 +29,12 @@ logger = init_logger(__name__)
29 class GritLMMeanPool(nn.Module):
30 """As `MeanPool`, but only includes non-instruction tokens."""
31
32 - def __init__(self, model_config: ModelConfig):
32 + def __init__(self, renderer_config: RendererConfig):
33 super().__init__()
34
35 - self.model_config = model_config
35 + self.renderer_config = renderer_config
36
37 - tokenizer = cached_tokenizer_from_config(self.model_config)
37 + tokenizer = cached_tokenizer_from_config(self.renderer_config)
38
39 # Collect the tokens needed for pattern matching.
40 # "▁<" is different from "_<". The former uses "▁" to indicate that
@@ -174,10 +174,10 @@ class GritLMMeanPool(nn.Module):
174
175
176 class GritLMPooler(Pooler):
177 - def __init__(self, model_config: ModelConfig):
177 + def __init__(self, renderer_config: RendererConfig):
178 super().__init__()
179
180 - self.pooling = GritLMMeanPool(model_config)
180 + self.pooling = GritLMMeanPool(renderer_config)
181 self.head = PoolerHead(PoolerNormalize())
182
183 def get_supported_tasks(self) -> Set[PoolingTask]:
@@ -238,6 +238,6 @@ class GritLM(LlamaForCausalLM):
238 self.pooler = DispatchPooler(
239 {
240 "token_embed": Pooler.for_token_embed(pooler_config),
241 - "embed": GritLMPooler(vllm_config.model_config),
241 + "embed": GritLMPooler(vllm_config.renderer_config),
242 }
243 )
vllm/model_executor/models/interfaces.py
+6 -4
@@ -19,7 +19,7 @@ from torch import Tensor
19 from transformers.models.whisper.tokenization_whisper import LANGUAGES
20 from typing_extensions import Self, TypeIs
21
22 -from vllm.config import ModelConfig, SpeechToTextConfig
22 +from vllm.config import RendererConfig, SpeechToTextConfig
23 from vllm.inputs import TokensPrompt
24 from vllm.inputs.data import PromptType
25 from vllm.logger import init_logger
@@ -887,7 +887,7 @@ class SupportsTranscription(Protocol):
887 cls,
888 audio: np.ndarray,
889 stt_config: SpeechToTextConfig,
890 - model_config: ModelConfig,
890 + renderer_config: RendererConfig,
891 language: str | None,
892 task_type: Literal["transcribe", "translate"],
893 request_prompt: str,
@@ -930,7 +930,9 @@ class SupportsTranscription(Protocol):
930
931 @classmethod
932 def get_speech_to_text_config(
933 - cls, model_config: ModelConfig, task_type: Literal["transcribe", "translate"]
933 + cls,
934 + renderer_config: RendererConfig,
935 + task_type: Literal["transcribe", "translate"],
936 ) -> SpeechToTextConfig:
937 """Get the speech to text config for the ASR model."""
938 ...
@@ -940,7 +942,7 @@ class SupportsTranscription(Protocol):
942 cls,
943 audio_duration_s: float,
944 stt_config: SpeechToTextConfig,
943 - model_config: ModelConfig,
945 + renderer_config: RendererConfig,
946 ) -> int | None:
947 """
948 Map from audio duration to number of audio tokens produced by the ASR
vllm/model_executor/models/interns1.py
+1 -1
@@ -182,7 +182,7 @@ class InternS1ProcessingInfo(BaseProcessingInfo):
182 def get_hf_processor(self, **kwargs: object) -> InternVLProcessor:
183 hf_processor = self.ctx.get_hf_processor(InternVLProcessor, **kwargs)
184 hf_processor.video_processor = cached_video_processor_from_config(
185 - self.ctx.model_config,
185 + self.ctx.renderer_config,
186 processor_cls=InternVLVideoProcessor,
187 size=hf_processor.image_processor.size,
188 **kwargs,
vllm/model_executor/models/nano_nemotron_vl.py
+7 -6
@@ -1169,16 +1169,17 @@ class NemotronH_Nano_VL_V2(
1169 self.mlp1 = self.mlp1.to(self.language_model.config.dtype)
1170
1171 self.config = config
1172 - self.model_config = vllm_config.model_config
1172
1173 # Pre-tokenize special tokens for video processing
1174 # to avoid repeated tokenization
1176 - tokenizer = cached_tokenizer_from_config(vllm_config.model_config)
1177 - self._img_start_token_ids = tokenizer.encode(
1175 + self._tokenizer = cached_tokenizer_from_config(vllm_config.renderer_config)
1176 + self._img_start_token_ids = self._tokenizer.encode(
1177 IMG_START, add_special_tokens=False
1178 )
1180 - self._img_end_token_ids = tokenizer.encode(IMG_END, add_special_tokens=False)
1181 - self._img_context_token_ids = tokenizer.encode(
1179 + self._img_end_token_ids = self._tokenizer.encode(
1180 + IMG_END, add_special_tokens=False
1181 + )
1182 + self._img_context_token_ids = self._tokenizer.encode(
1183 IMG_CONTEXT, add_special_tokens=False
1184 )
1185
@@ -1364,7 +1365,7 @@ class NemotronH_Nano_VL_V2(
1365 input_embeds for the LLM.
1366 """
1367 device = video_embeddings.device
1367 - tokenizer = cached_tokenizer_from_config(self.model_config)
1368 + tokenizer = self._tokenizer
1369
1370 # Generate video replacement token IDs using get_video_repl
1371 # This tokenizes each frame separator independently, then uses pre-tokenized
vllm/model_executor/models/nemotron_vl.py
+1 -1
@@ -347,7 +347,7 @@ class NemotronVLProcessingInfo(BaseInternVLProcessingInfo):
347
348 def get_image_processor(self, **kwargs: object):
349 return cached_image_processor_from_config(
350 - self.ctx.model_config,
350 + self.ctx.renderer_config,
351 **kwargs,
352 )
353
vllm/model_executor/models/pixtral.py
+1 -1
@@ -193,7 +193,7 @@ class PixtralProcessorAdapter:
193
194 class PixtralProcessingInfo(BaseProcessingInfo):
195 def get_tokenizer(self) -> MistralTokenizer:
196 - tokenizer = cached_tokenizer_from_config(self.ctx.model_config)
196 + tokenizer = cached_tokenizer_from_config(self.ctx.renderer_config)
197 if not isinstance(tokenizer, MistralTokenizer):
198 raise ValueError("This model requires `--tokenizer-mode mistral`")
199
vllm/model_executor/models/voxtral.py
+12 -10
@@ -20,7 +20,7 @@ from mistral_common.tokens.tokenizers.audio import Audio, AudioEncoder
20 from transformers import BatchFeature, TensorType, WhisperConfig
21 from transformers.tokenization_utils_base import TextInput
22
23 -from vllm.config import ModelConfig, SpeechToTextConfig, VllmConfig
23 +from vllm.config import RendererConfig, SpeechToTextConfig, VllmConfig
24 from vllm.config.multimodal import BaseDummyOptions
25 from vllm.inputs.data import PromptType
26 from vllm.logger import init_logger
@@ -176,7 +176,7 @@ class VoxtralProcessorAdapter:
176
177 class VoxtralProcessingInfo(BaseProcessingInfo):
178 def get_tokenizer(self) -> MistralTokenizer:
179 - tokenizer = cached_tokenizer_from_config(self.ctx.model_config)
179 + tokenizer = cached_tokenizer_from_config(self.ctx.renderer_config)
180 if not isinstance(tokenizer, MistralTokenizer):
181 raise ValueError("This model requires `--tokenizer-mode mistral`")
182
@@ -339,7 +339,7 @@ class VoxtralForConditionalGeneration(
339
340 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
341 super().__init__()
342 - self.tokenizer = cached_tokenizer_from_config(vllm_config.model_config)
342 + self.tokenizer = cached_tokenizer_from_config(vllm_config.renderer_config)
343
344 # update quant config to so that ignored module and target module names
345 # match the vLLM model names
@@ -450,9 +450,11 @@ class VoxtralForConditionalGeneration(
450
451 @classmethod
452 def get_speech_to_text_config(
453 - cls, model_config: ModelConfig, task_type: str
453 + cls,
454 + renderer_config: RendererConfig,
455 + task_type: str,
456 ) -> SpeechToTextConfig:
455 - tokenizer = cached_tokenizer_from_config(model_config)
457 + tokenizer = cached_tokenizer_from_config(renderer_config)
458 audio_config = tokenizer.instruct.audio_encoder.audio_config
459 max_audio_clip_s = audio_config.chunk_length_s
460 sample_rate = audio_config.sampling_rate
@@ -468,17 +470,17 @@ class VoxtralForConditionalGeneration(
470 def get_generation_prompt(
471 cls,
472 audio: np.ndarray,
471 - model_config: ModelConfig,
473 + renderer_config: RendererConfig, # not needed here
474 stt_config: SpeechToTextConfig,
475 language: str | None,
476 task_type: Literal["transcribe", "translate"],
477 request_prompt: str,
478 to_language: str | None,
479 ) -> PromptType:
478 - tokenizer = cached_tokenizer_from_config(model_config)
480 + tokenizer = cached_tokenizer_from_config(renderer_config)
481 audio = Audio(audio, int(stt_config.sample_rate), format="wav") # lossless
482 req = TranscriptionRequest(
481 - model=model_config.model,
483 + model=renderer_config.model_config.model,
484 audio=RawAudio.from_audio(audio),
485 language=language,
486 )
@@ -494,14 +496,14 @@ class VoxtralForConditionalGeneration(
496 cls,
497 audio_duration_s: float,
498 stt_config: SpeechToTextConfig,
497 - model_config: ModelConfig,
499 + renderer_config: RendererConfig,
500 ) -> int | None:
501 """
502 Map from audio duration to number of audio tokens produced by the ASR
503 model, without running a forward pass.
504 This is used for estimating the amount of processing for this audio.
505 """
504 - tokenizer = cached_tokenizer_from_config(model_config)
506 + tokenizer = cached_tokenizer_from_config(renderer_config)
507 adapter = VoxtralProcessorAdapter(tokenizer)
508 return adapter.get_num_audio_tokens(
509 int(audio_duration_s * stt_config.sample_rate)
vllm/model_executor/models/whisper.py
+8 -6
@@ -19,7 +19,7 @@ from transformers.models.whisper.modeling_whisper import sinusoids
19 from vllm.attention.backends.abstract import AttentionType
20 from vllm.attention.layer import Attention, MultiHeadAttention
21 from vllm.attention.layers.cross_attention import CrossAttention
22 -from vllm.config import CacheConfig, ModelConfig, SpeechToTextConfig, VllmConfig
22 +from vllm.config import CacheConfig, RendererConfig, SpeechToTextConfig, VllmConfig
23 from vllm.config.multimodal import BaseDummyOptions
24 from vllm.distributed import get_tensor_model_parallel_world_size
25 from vllm.inputs.data import PromptType
@@ -811,7 +811,7 @@ class WhisperForConditionalGeneration(
811 def get_generation_prompt(
812 cls,
813 audio: np.ndarray,
814 - model_config: ModelConfig, # not needed here
814 + renderer_config: RendererConfig, # not needed here
815 stt_config: SpeechToTextConfig,
816 language: str | None,
817 task_type: Literal["transcribe", "translate"],
@@ -847,9 +847,11 @@ class WhisperForConditionalGeneration(
847
848 @classmethod
849 def get_speech_to_text_config(
850 - cls, model_config: ModelConfig, task_type: str
850 + cls,
851 + renderer_config: RendererConfig,
852 + task_type: str,
853 ) -> SpeechToTextConfig:
852 - processor = cached_processor_from_config(model_config)
854 + processor = cached_processor_from_config(renderer_config)
855
856 return SpeechToTextConfig(
857 max_audio_clip_s=processor.feature_extractor.chunk_length,
@@ -861,9 +863,9 @@ class WhisperForConditionalGeneration(
863 cls,
864 audio_duration_s: float,
865 stt_config: SpeechToTextConfig,
864 - model_config: ModelConfig,
866 + renderer_config: RendererConfig,
867 ) -> int | None:
866 - processor = cached_processor_from_config(model_config)
868 + processor = cached_processor_from_config(renderer_config)
869 hop_length = processor.feature_extractor.hop_length
870 assert hop_length is not None
871 # NOTE(NickLucche) user can't pass encoder
vllm/multimodal/cache.py
+10 -12
@@ -31,7 +31,7 @@ from .inputs import (
31 )
32
33 if TYPE_CHECKING:
34 - from vllm.config import ModelConfig, VllmConfig
34 + from vllm.config import ModelConfig, RendererConfig, VllmConfig
35
36 from .processing import ResolvedPromptUpdate
37 from .registry import MultiModalRegistry
@@ -561,13 +561,13 @@ class ShmObjectStoreSenderCache(BaseMultiModalProcessorCache):
561
562
563 def _enable_processor_cache(
564 - model_config: "ModelConfig",
564 + renderer_config: "RendererConfig",
565 mm_registry: "MultiModalRegistry",
566 ) -> bool:
567 - if not mm_registry.supports_multimodal_inputs(model_config):
567 + if not mm_registry.supports_multimodal_inputs(renderer_config):
568 return False
569
570 - mm_config = model_config.get_multimodal_config()
570 + mm_config = renderer_config.model_config.get_multimodal_config()
571 return mm_config.mm_processor_cache_gb > 0
572
573
@@ -599,7 +599,7 @@ def processor_cache_from_config(
599 """Return a `BaseMultiModalProcessorCache`, if enabled."""
600 model_config = vllm_config.model_config
601
602 - if not _enable_processor_cache(model_config, mm_registry):
602 + if not _enable_processor_cache(vllm_config.renderer_config, mm_registry):
603 return None
604
605 if not _enable_ipc_cache(vllm_config):
@@ -611,14 +611,14 @@ def processor_cache_from_config(
611
612
613 def processor_only_cache_from_config(
614 - model_config: "ModelConfig",
614 + renderer_config: "RendererConfig",
615 mm_registry: "MultiModalRegistry",
616 ):
617 """Return a `MultiModalProcessorOnlyCache`, if enabled."""
618 - if not _enable_processor_cache(model_config, mm_registry):
618 + if not _enable_processor_cache(renderer_config, mm_registry):
619 return None
620
621 - return MultiModalProcessorOnlyCache(model_config)
621 + return MultiModalProcessorOnlyCache(renderer_config.model_config)
622
623
624 class BaseMultiModalReceiverCache(
@@ -787,7 +787,7 @@ def engine_receiver_cache_from_config(
787 """
788 model_config = vllm_config.model_config
789
790 - if not _enable_processor_cache(model_config, mm_registry):
790 + if not _enable_processor_cache(vllm_config.renderer_config, mm_registry):
791 return None
792
793 if not _enable_ipc_cache(vllm_config):
@@ -809,9 +809,7 @@ def worker_receiver_cache_from_config(
809 Return a `BaseMultiModalReceiverCache` only when IPC caching is enabled and
810 mm_processor_cache_type=="shm".
811 """
812 - model_config = vllm_config.model_config
813 -
814 - if not _enable_processor_cache(model_config, mm_registry):
812 + if not _enable_processor_cache(vllm_config.renderer_config, mm_registry):
813 return None
814
815 if not _enable_ipc_cache(vllm_config):
vllm/multimodal/processing.py
+23 -5
@@ -23,7 +23,7 @@ import torch
23 from typing_extensions import TypeVar, assert_never
24
25 from vllm.logger import init_logger
26 -from vllm.tokenizers import TokenizerLike
26 +from vllm.tokenizers import TokenizerLike, cached_tokenizer_from_config
27 from vllm.transformers_utils.processor import cached_processor_from_config
28 from vllm.utils.collection_utils import flatten_2d_lists, full_groupby
29 from vllm.utils.func_utils import get_allowed_kwarg_only_overrides
@@ -53,7 +53,7 @@ if TYPE_CHECKING:
53 from transformers.feature_extraction_utils import BatchFeature
54 from transformers.processing_utils import ProcessorMixin
55
56 - from vllm.config import ModelConfig
56 + from vllm.config import ModelConfig, RendererConfig
57
58 from .cache import BaseMultiModalProcessorCache
59 from .profiling import BaseDummyInputsBuilder
@@ -63,6 +63,7 @@ else:
63 ProcessorMixin = object
64
65 ModelConfig = object
66 + RendererConfig = object
67
68 BaseMultiModalProcessorCache = object
69
@@ -945,12 +946,29 @@ class InputProcessingContext:
946 modify the inputs.
947 """
948
948 - model_config: ModelConfig
949 - """The configuration of the model."""
949 + renderer_config: RendererConfig
950 + """The configuration of the renderer."""
951
952 tokenizer: TokenizerLike | None
953 """The tokenizer used to tokenize the inputs."""
954
955 + @classmethod
956 + def from_config(
957 + cls,
958 + renderer_config: RendererConfig,
959 + *,
960 + tokenizer: TokenizerLike | None = None,
961 + ):
962 + if tokenizer is None and not renderer_config.skip_tokenizer_init:
963 + tokenizer = cached_tokenizer_from_config(renderer_config)
964 +
965 + return cls(renderer_config, tokenizer)
966 +
967 + @property
968 + def model_config(self) -> ModelConfig:
969 + """The configuration of the model."""
970 + return self.renderer_config.model_config
971 +
972 def get_tokenizer(self) -> TokenizerLike:
973 if self.tokenizer is None:
974 raise ValueError(
@@ -1047,7 +1065,7 @@ class InputProcessingContext:
1065 typ = ProcessorMixin
1066
1067 return cached_processor_from_config(
1050 - self.model_config,
1068 + self.renderer_config,
1069 processor_cls=typ,
1070 tokenizer=self.tokenizer,
1071 **kwargs,
vllm/multimodal/registry.py
+30 -34
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, Generic, Protocol, TypeVar, cast
6
7 from vllm.config.multimodal import BaseDummyOptions
8 from vllm.logger import init_logger
9 -from vllm.tokenizers import TokenizerLike, cached_tokenizer_from_config
9 +from vllm.tokenizers import TokenizerLike
10
11 from .cache import BaseMultiModalProcessorCache
12 from .processing import (
@@ -22,7 +22,7 @@ from .profiling import (
22 )
23
24 if TYPE_CHECKING:
25 - from vllm.config import ModelConfig
25 + from vllm.config import ModelConfig, RendererConfig
26 from vllm.model_executor.models.interfaces import SupportsMultiModal
27
28 logger = init_logger(__name__)
@@ -114,17 +114,18 @@ class MultiModalRegistry:
114
115 return mm_options if len(mm_options) > 0 else None
116
117 - def supports_multimodal_inputs(self, model_config: "ModelConfig") -> bool:
117 + def supports_multimodal_inputs(self, renderer_config: "RendererConfig") -> bool:
118 """
119 Checks if the model supports multimodal inputs.
120 Returns True if the model is multimodal with any non-zero supported
121 modalities, otherwise returns False, effectively running in
122 text-only mode.
123 """
124 + model_config = renderer_config.model_config
125 if not model_config.is_multimodal_model:
126 return False
127
127 - info = self._create_processing_info(model_config, tokenizer=None)
128 + info = self._create_processing_info(renderer_config, tokenizer=None)
129 supported_modalities = info.get_supported_mm_limits()
130
131 mm_config = model_config.get_multimodal_config()
@@ -144,7 +145,7 @@ class MultiModalRegistry:
145
146 def get_max_tokens_per_item_by_modality(
147 self,
147 - model_config: "ModelConfig",
148 + renderer_config: "RendererConfig",
149 *,
150 cache: BaseMultiModalProcessorCache | None = None,
151 profiler_limits: Mapping[str, int] | None = None,
@@ -153,10 +154,11 @@ class MultiModalRegistry:
154 Get the maximum number of tokens per data item from each modality based
155 on underlying model configuration.
156 """
157 + model_config = renderer_config.model_config
158 if not model_config.is_multimodal_model:
159 return {}
160
159 - processor = self.create_processor(model_config, cache=cache)
161 + processor = self.create_processor(renderer_config, cache=cache)
162 profiler: MultiModalProfiler = MultiModalProfiler(processor)
163
164 seq_len = model_config.max_model_len
@@ -171,7 +173,7 @@ class MultiModalRegistry:
173
174 def get_mm_limits_per_prompt(
175 self,
174 - model_config: "ModelConfig",
176 + renderer_config: "RendererConfig",
177 *,
178 cache: BaseMultiModalProcessorCache | None = None,
179 ) -> Mapping[str, int]:
@@ -179,10 +181,11 @@ class MultiModalRegistry:
181 Get the maximum number of multi-modal input instances for each modality
182 that are allowed per prompt for a model class.
183 """
184 + model_config = renderer_config.model_config
185 if not model_config.is_multimodal_model:
186 return {}
187
185 - processor = self.create_processor(model_config, cache=cache)
188 + processor = self.create_processor(renderer_config, cache=cache)
189 profiler: MultiModalProfiler = MultiModalProfiler(processor)
190 return profiler.get_mm_limits()
191
@@ -228,30 +231,21 @@ class MultiModalRegistry:
231 assert hasattr(model_cls, "_processor_factory")
232 return cast("SupportsMultiModal", model_cls)
233
231 - def _create_processing_ctx(
232 - self,
233 - model_config: "ModelConfig",
234 - tokenizer: TokenizerLike | None = None,
235 - ) -> InputProcessingContext:
236 - if tokenizer is None and not model_config.skip_tokenizer_init:
237 - tokenizer = cached_tokenizer_from_config(model_config)
238 -
239 - return InputProcessingContext(model_config, tokenizer)
240 -
234 def _create_processing_info(
235 self,
243 - model_config: "ModelConfig",
236 + renderer_config: "RendererConfig",
237 *,
238 tokenizer: TokenizerLike | None = None,
239 ) -> BaseProcessingInfo:
247 - model_cls = self._get_model_cls(model_config)
240 + model_cls = self._get_model_cls(renderer_config.model_config)
241 factories = model_cls._processor_factory
249 - ctx = self._create_processing_ctx(model_config, tokenizer)
242 +
243 + ctx = InputProcessingContext.from_config(renderer_config, tokenizer=tokenizer)
244 return factories.info(ctx)
245
246 def create_processor(
247 self,
254 - model_config: "ModelConfig",
248 + renderer_config: "RendererConfig",
249 *,
250 tokenizer: TokenizerLike | None = None,
251 cache: BaseMultiModalProcessorCache | None = None,
@@ -259,19 +253,19 @@ class MultiModalRegistry:
253 """
254 Create a multi-modal processor for a specific model and tokenizer.
255 """
256 + model_config = renderer_config.model_config
257 if not model_config.is_multimodal_model:
258 raise ValueError(f"{model_config.model} is not a multimodal model")
259
260 model_cls = self._get_model_cls(model_config)
261 factories = model_cls._processor_factory
262
268 - ctx = self._create_processing_ctx(model_config, tokenizer)
269 -
263 + ctx = InputProcessingContext.from_config(renderer_config, tokenizer=tokenizer)
264 return factories.build_processor(ctx, cache=cache)
265
266 def get_decoder_dummy_data(
267 self,
274 - model_config: "ModelConfig",
268 + renderer_config: "RendererConfig",
269 seq_len: int,
270 mm_counts: Mapping[str, int] | None = None,
271 *,
@@ -280,15 +274,15 @@ class MultiModalRegistry:
274 """
275 Create dummy data for profiling the memory usage of a model.
276
283 - The model is identified by `model_config`.
277 + The model is identified by `renderer_config`.
278 """
285 - processor = self.create_processor(model_config, cache=cache)
279 + processor = self.create_processor(renderer_config, cache=cache)
280 profiler: MultiModalProfiler = MultiModalProfiler(processor)
281
282 # Extract configurable options from multimodal config.
283 # Only include modalities that use advanced option types so legacy
284 # count-only behavior remains unchanged.
291 - mm_options = self._extract_mm_options(model_config)
285 + mm_options = self._extract_mm_options(renderer_config.model_config)
286
287 dummy_data = profiler.get_decoder_dummy_data(seq_len, mm_counts, mm_options)
288
@@ -304,7 +298,7 @@ class MultiModalRegistry:
298
299 def get_encoder_dummy_data(
300 self,
307 - model_config: "ModelConfig",
301 + renderer_config: "RendererConfig",
302 seq_len: int,
303 mm_counts: Mapping[str, int] | None = None,
304 *,
@@ -313,15 +307,15 @@ class MultiModalRegistry:
307 """
308 Create dummy data for profiling the memory usage of a model.
309
316 - The model is identified by `model_config`.
310 + The model is identified by `renderer_config`.
311 """
318 - processor = self.create_processor(model_config, cache=cache)
312 + processor = self.create_processor(renderer_config, cache=cache)
313 profiler: MultiModalProfiler = MultiModalProfiler(processor)
314
315 # Extract configurable options from multimodal config.
316 # Only include modalities that use advanced option types so legacy
317 # count-only behavior remains unchanged.
324 - mm_options = self._extract_mm_options(model_config)
318 + mm_options = self._extract_mm_options(renderer_config.model_config)
319
320 dummy_data = profiler.get_encoder_dummy_data(seq_len, mm_counts, mm_options)
321
@@ -336,13 +330,15 @@ class MultiModalRegistry:
330
331 return dummy_data
332
339 - def get_encdec_max_encoder_len(self, model_config: "ModelConfig") -> int:
333 + def get_encdec_max_encoder_len(self, renderer_config: "RendererConfig") -> int:
334 """
335 Get the maximum length of the encoder input for encoder-decoder models.
336 """
337 + model_config = renderer_config.model_config
338 if not model_config.is_encoder_decoder:
339 return 0
345 - max_tokens = self.get_max_tokens_per_item_by_modality(model_config)
340 +
341 + max_tokens = self.get_max_tokens_per_item_by_modality(renderer_config)
342 if not max_tokens:
343 # TODO - this function assumes encoder-decoder models are
344 # multimodal. This will need to change when adding support for more
vllm/tokenizers/registry.py
+12 -12
@@ -24,7 +24,7 @@ from vllm.utils.import_utils import resolve_obj_by_qualname
24 from .protocol import TokenizerLike
25
26 if TYPE_CHECKING:
27 - from vllm.config import ModelConfig
27 + from vllm.config import RendererConfig
28
29 logger = init_logger(__name__)
30
@@ -205,18 +205,18 @@ def get_tokenizer(
205 cached_get_tokenizer = lru_cache(get_tokenizer)
206
207
208 -def cached_tokenizer_from_config(model_config: "ModelConfig", **kwargs):
208 +def cached_tokenizer_from_config(renderer_config: "RendererConfig", **kwargs):
209 return cached_get_tokenizer(
210 - model_config.tokenizer,
211 - tokenizer_mode=model_config.tokenizer_mode,
212 - revision=model_config.tokenizer_revision,
213 - trust_remote_code=model_config.trust_remote_code,
210 + renderer_config.tokenizer,
211 + tokenizer_mode=renderer_config.tokenizer_mode,
212 + revision=renderer_config.tokenizer_revision,
213 + trust_remote_code=renderer_config.trust_remote_code,
214 **kwargs,
215 )
216
217
218 -def init_tokenizer_from_config(model_config: "ModelConfig"):
219 - runner_type = model_config.runner_type
218 +def init_tokenizer_from_config(renderer_config: "RendererConfig"):
219 + runner_type = renderer_config.model_config.runner_type
220 if runner_type == "generate" or runner_type == "draft":
221 truncation_side = "left"
222 elif runner_type == "pooling":
@@ -225,9 +225,9 @@ def init_tokenizer_from_config(model_config: "ModelConfig"):
225 assert_never(runner_type)
226
227 return get_tokenizer(
228 - model_config.tokenizer,
229 - tokenizer_mode=model_config.tokenizer_mode,
230 - trust_remote_code=model_config.trust_remote_code,
231 - revision=model_config.tokenizer_revision,
228 + renderer_config.tokenizer,
229 + tokenizer_mode=renderer_config.tokenizer_mode,
230 + trust_remote_code=renderer_config.trust_remote_code,
231 + revision=renderer_config.tokenizer_revision,
232 truncation_side=truncation_side,
233 )
vllm/transformers_utils/processor.py
+17 -11
@@ -23,7 +23,7 @@ from vllm.transformers_utils.utils import convert_model_repo_to_path
23 from vllm.utils.func_utils import get_allowed_kwarg_only_overrides
24
25 if TYPE_CHECKING:
26 - from vllm.config import ModelConfig
26 + from vllm.config import ModelConfig, RendererConfig
27
28 _P = TypeVar("_P", bound=ProcessorMixin, default=ProcessorMixin)
29 _V = TypeVar("_V", bound=BaseVideoProcessor, default=BaseVideoProcessor)
@@ -233,17 +233,18 @@ def cached_get_processor_without_dynamic_kwargs(
233
234
235 def cached_processor_from_config(
236 - model_config: "ModelConfig",
236 + renderer_config: "RendererConfig",
237 processor_cls: type[_P] | tuple[type[_P], ...] = ProcessorMixin,
238 **kwargs: Any,
239 ) -> _P:
240 + model_config = renderer_config.model_config
241 if is_gguf(model_config.model):
241 - assert not is_gguf(model_config.tokenizer), (
242 + assert not is_gguf(renderer_config.tokenizer), (
243 "For multimodal GGUF models, the original tokenizer "
244 "should be used to correctly load processor."
245 )
245 - model = model_config.tokenizer
246 - revision = model_config.tokenizer_revision
246 + model = renderer_config.tokenizer
247 + revision = renderer_config.tokenizer_revision
248 else:
249 model = model_config.model
250 revision = model_config.revision
@@ -297,9 +298,11 @@ cached_get_feature_extractor = lru_cache(get_feature_extractor)
298
299
300 def cached_feature_extractor_from_config(
300 - model_config: "ModelConfig",
301 + renderer_config: "RendererConfig",
302 **kwargs: Any,
303 ):
304 + model_config = renderer_config.model_config
305 +
306 return cached_get_feature_extractor(
307 model_config.model,
308 revision=model_config.revision,
@@ -348,16 +351,17 @@ cached_get_image_processor = lru_cache(get_image_processor)
351
352
353 def cached_image_processor_from_config(
351 - model_config: "ModelConfig",
354 + renderer_config: "RendererConfig",
355 **kwargs: Any,
356 ):
357 + model_config = renderer_config.model_config
358 if is_gguf(model_config.model):
355 - assert not is_gguf(model_config.tokenizer), (
359 + assert not is_gguf(renderer_config.tokenizer), (
360 "For multimodal GGUF models, the original tokenizer "
361 "should be used to correctly load image processor."
362 )
359 - model = model_config.tokenizer
360 - revision = model_config.tokenizer_revision
363 + model = renderer_config.tokenizer
364 + revision = renderer_config.tokenizer_revision
365 else:
366 model = model_config.model
367 revision = model_config.revision
@@ -411,10 +415,12 @@ cached_get_video_processor = lru_cache(get_video_processor)
415
416
417 def cached_video_processor_from_config(
414 - model_config: "ModelConfig",
418 + renderer_config: "RendererConfig",
419 processor_cls: type[_V] | None = None,
420 **kwargs: Any,
421 ):
422 + model_config = renderer_config.model_config
423 +
424 return cached_get_video_processor(
425 model_config.model,
426 revision=model_config.revision,
vllm/v1/core/encoder_cache_manager.py
+4 -4
@@ -10,7 +10,7 @@ from vllm.multimodal import MultiModalRegistry
10 from vllm.v1.request import Request
11
12 if TYPE_CHECKING:
13 - from vllm.config import ModelConfig, SchedulerConfig
13 + from vllm.config import RendererConfig, SchedulerConfig
14
15 logger = init_logger(__name__)
16
@@ -250,7 +250,7 @@ class EncoderCacheManager:
250
251
252 def compute_encoder_budget(
253 - model_config: "ModelConfig",
253 + renderer_config: "RendererConfig",
254 scheduler_config: "SchedulerConfig",
255 mm_registry: MultiModalRegistry,
256 ) -> tuple[int, int]:
@@ -263,9 +263,9 @@ def compute_encoder_budget(
263 - Space budget for encoder cache size, measured in number of tokens
264 from the input sequence.
265 """
266 - if mm_registry.supports_multimodal_inputs(model_config):
266 + if mm_registry.supports_multimodal_inputs(renderer_config):
267 max_tokens_by_modality = mm_registry.get_max_tokens_per_item_by_modality(
268 - model_config
268 + renderer_config
269 )
270
271 return compute_mm_encoder_budget(
vllm/v1/core/sched/scheduler.py
+1 -1
@@ -164,7 +164,7 @@ class Scheduler(SchedulerInterface):
164 # This can be changed when we make encoder cache for embedding caching
165 # across requests.
166 encoder_compute_budget, encoder_cache_size = compute_encoder_budget(
167 - model_config=vllm_config.model_config,
167 + renderer_config=vllm_config.renderer_config,
168 scheduler_config=vllm_config.scheduler_config,
169 mm_registry=mm_registry,
170 )
vllm/v1/engine/async_llm.py
+4 -3
@@ -91,6 +91,7 @@ class AsyncLLM(EngineClient):
91 # Ensure we can serialize custom transformer configs
92 maybe_register_config_serialize_by_value()
93
94 + self.renderer_config = vllm_config.renderer_config
95 self.model_config = vllm_config.model_config
96 self.vllm_config = vllm_config
97 self.observability_config = vllm_config.observability_config
@@ -108,15 +109,15 @@ class AsyncLLM(EngineClient):
109 "enabling logging without default stat loggers."
110 )
111
111 - if self.model_config.skip_tokenizer_init:
112 + if self.renderer_config.skip_tokenizer_init:
113 tokenizer = None
114 else:
114 - tokenizer = init_tokenizer_from_config(self.model_config)
115 + tokenizer = init_tokenizer_from_config(self.renderer_config)
116
117 self.input_processor = InputProcessor(self.vllm_config, tokenizer)
118 self.io_processor = get_io_processor(
119 self.vllm_config,
119 - self.model_config.io_processor_plugin,
120 + self.renderer_config.io_processor_plugin,
121 )
122
123 # OutputProcessor (converts EngineCoreOutputs --> RequestOutput).
vllm/v1/engine/input_processor.py
+4 -3
@@ -43,6 +43,7 @@ class InputProcessor:
43 mm_registry: MultiModalRegistry = MULTIMODAL_REGISTRY,
44 ) -> None:
45 self.vllm_config = vllm_config
46 + self.renderer_config = vllm_config.renderer_config
47 self.model_config = vllm_config.model_config
48 self.cache_config = vllm_config.cache_config
49 self.lora_config = vllm_config.lora_config
@@ -54,7 +55,7 @@ class InputProcessor:
55 self.mm_processor_cache = processor_cache_from_config(vllm_config, mm_registry)
56
57 self.input_preprocessor = InputPreprocessor(
57 - self.model_config,
58 + self.renderer_config,
59 tokenizer,
60 mm_registry,
61 mm_processor_cache=self.mm_processor_cache,
@@ -252,7 +253,7 @@ class InputProcessor:
253 if not params.structured_outputs or not self.structured_outputs_config:
254 return
255
255 - if self.model_config.skip_tokenizer_init and params.structured_outputs:
256 + if self.renderer_config.skip_tokenizer_init and params.structured_outputs:
257 raise ValueError(
258 "Structured outputs requires a tokenizer so it can't be used with 'skip_tokenizer_init'" # noqa: E501
259 )
@@ -582,7 +583,7 @@ class InputProcessor:
583 if prompt_type == "encoder" and model_config.is_multimodal_model:
584 mm_registry = self.input_preprocessor.mm_registry
585 mm_processor = mm_registry.create_processor(
585 - model_config,
586 + self.renderer_config,
587 tokenizer=tokenizer,
588 )
589 assert isinstance(mm_processor, EncDecMultiModalProcessor)
vllm/v1/engine/llm_engine.py
+4 -3
@@ -60,6 +60,7 @@ class LLMEngine:
60 ) -> None:
61 self.vllm_config = vllm_config
62 self.observability_config = vllm_config.observability_config
63 + self.renderer_config = vllm_config.renderer_config
64 self.model_config = vllm_config.model_config
65 self.cache_config = vllm_config.cache_config
66
@@ -83,15 +84,15 @@ class LLMEngine:
84 self.dp_group = None
85 self.should_execute_dummy_batch = False
86
86 - if self.model_config.skip_tokenizer_init:
87 + if self.renderer_config.skip_tokenizer_init:
88 tokenizer = None
89 else:
89 - tokenizer = init_tokenizer_from_config(self.model_config)
90 + tokenizer = init_tokenizer_from_config(self.renderer_config)
91
92 self.input_processor = InputProcessor(self.vllm_config, tokenizer)
93 self.io_processor = get_io_processor(
94 self.vllm_config,
94 - self.model_config.io_processor_plugin,
95 + self.renderer_config.io_processor_plugin,
96 )
97
98 # OutputProcessor (convert EngineCoreOutputs --> RequestOutput).
vllm/v1/spec_decode/eagle.py
+1 -1
@@ -85,7 +85,7 @@ class EagleProposer:
85 # Multi-modal data support
86 self.mm_registry = MULTIMODAL_REGISTRY
87 self.supports_mm_inputs = self.mm_registry.supports_multimodal_inputs(
88 - vllm_config.model_config
88 + vllm_config.renderer_config
89 )
90
91 self.attn_metadata_builder: AttentionMetadataBuilder | None = None
vllm/v1/structured_output/__init__.py
+6 -12
@@ -63,7 +63,7 @@ class StructuredOutputManager:
63 max_workers = max(1, min(multiprocessing.cpu_count() // 2, 8))
64 self.executor_for_fillmask = ThreadPoolExecutor(max_workers=max_workers)
65
66 - if not self.vllm_config.model_config.skip_tokenizer_init:
66 + if not vllm_config.renderer_config.skip_tokenizer_init:
67 # The default max_workers if not specified is the number of
68 # CPUs * 5, which is way too high since these tasks are CPU-bound,
69 # not I/O bound. We also know we would never dominate CPU usage
@@ -71,21 +71,15 @@ class StructuredOutputManager:
71 # of CPUs.
72 max_workers = max(1, (multiprocessing.cpu_count() + 1) // 2)
73 self.executor = ThreadPoolExecutor(max_workers=max_workers)
74 - self.tokenizer = init_tokenizer_from_config(
75 - model_config=self.vllm_config.model_config
76 - )
77 - reasoning_parser = (
78 - self.vllm_config.structured_outputs_config.reasoning_parser
79 - )
74 + self.tokenizer = init_tokenizer_from_config(vllm_config.renderer_config)
75 + reasoning_parser = vllm_config.structured_outputs_config.reasoning_parser
76 reasoning_parser_plugin = (
81 - self.vllm_config.structured_outputs_config.reasoning_parser_plugin
77 + vllm_config.structured_outputs_config.reasoning_parser_plugin
78 )
79 if reasoning_parser_plugin and len(reasoning_parser_plugin) > 3:
80 ReasoningParserManager.import_reasoning_parser(reasoning_parser_plugin)
81
86 - reasoning_parser = (
87 - self.vllm_config.structured_outputs_config.reasoning_parser
88 - )
82 + reasoning_parser = vllm_config.structured_outputs_config.reasoning_parser
83 if reasoning_parser:
84 reasoner_cls = ReasoningParserManager.get_reasoning_parser(
85 reasoning_parser
@@ -93,7 +87,7 @@ class StructuredOutputManager:
87 self.reasoner = reasoner_cls(tokenizer=self.tokenizer)
88
89 self.enable_in_reasoning = (
96 - self.vllm_config.structured_outputs_config.enable_in_reasoning
90 + vllm_config.structured_outputs_config.enable_in_reasoning
91 )
92
93 def grammar_init(self, request: Request) -> None:
vllm/v1/worker/gpu_model_runner.py
+4 -3
@@ -271,6 +271,7 @@ class GPUModelRunner(
271 device: torch.device,
272 ):
273 self.vllm_config = vllm_config
274 + self.renderer_config = vllm_config.renderer_config
275 self.model_config = vllm_config.model_config
276 self.cache_config = vllm_config.cache_config
277 self.compilation_config = vllm_config.compilation_config
@@ -335,7 +336,7 @@ class GPUModelRunner(
336 self.uses_mrope = model_config.uses_mrope
337 self.uses_xdrope_dim = model_config.uses_xdrope_dim
338 self.supports_mm_inputs = self.mm_registry.supports_multimodal_inputs(
338 - model_config
339 + self.renderer_config
340 )
341
342 if self.model_config.is_encoder_decoder:
@@ -558,7 +559,7 @@ class GPUModelRunner(
559
560 self.mm_budget = (
561 MultiModalBudget(
561 - self.model_config,
562 + self.renderer_config,
563 self.scheduler_config,
564 self.mm_registry,
565 )
@@ -3873,7 +3874,7 @@ class GPUModelRunner(
3874 assert self.mm_budget is not None
3875
3876 dummy_decoder_data = self.mm_registry.get_decoder_dummy_data(
3876 - model_config=self.model_config,
3877 + renderer_config=self.renderer_config,
3878 seq_len=self.max_model_len,
3879 mm_counts={modality: 1},
3880 cache=self.mm_budget.cache,
vllm/v1/worker/tpu_model_runner.py
+4 -3
@@ -143,6 +143,7 @@ class TPUModelRunner(LoRAModelRunnerMixin, KVConnectorModelRunnerMixin):
143 original_parallel_config: ParallelConfig | None = None,
144 ):
145 self.vllm_config = vllm_config
146 + self.renderer_config = vllm_config.renderer_config
147 self.model_config = vllm_config.model_config
148 self.cache_config = vllm_config.cache_config
149 self.lora_config = vllm_config.lora_config
@@ -222,7 +223,7 @@ class TPUModelRunner(LoRAModelRunnerMixin, KVConnectorModelRunnerMixin):
223 self.mm_registry = MULTIMODAL_REGISTRY
224 self.uses_mrope = model_config.uses_mrope
225 self.supports_mm_inputs = self.mm_registry.supports_multimodal_inputs(
225 - model_config
226 + self.renderer_config
227 )
228 # TODO: Support M-RoPE (e.g, Qwen2-VL)
229 assert not self.uses_mrope, "TPU does not support M-RoPE yet."
@@ -353,7 +354,7 @@ class TPUModelRunner(LoRAModelRunnerMixin, KVConnectorModelRunnerMixin):
354
355 self.mm_budget = (
356 MultiModalBudget(
356 - self.model_config,
357 + self.renderer_config,
358 self.scheduler_config,
359 self.mm_registry,
360 )
@@ -2038,7 +2039,7 @@ class TPUModelRunner(LoRAModelRunnerMixin, KVConnectorModelRunnerMixin):
2039 assert self.mm_budget is not None
2040
2041 dummy_decoder_data = self.mm_registry.get_decoder_dummy_data(
2041 - model_config=self.model_config,
2042 + renderer_config=self.renderer_config,
2043 seq_len=self.max_model_len,
2044 mm_counts={modality: 1},
2045 cache=self.mm_budget.cache,
vllm/v1/worker/utils.py
+12 -7
@@ -7,7 +7,7 @@ import torch
7
8 from vllm.attention.backends.abstract import AttentionBackend
9 from vllm.attention.layer import Attention
10 -from vllm.config import ModelConfig, SchedulerConfig, VllmConfig
10 +from vllm.config import RendererConfig, SchedulerConfig, VllmConfig
11 from vllm.model_executor.models.interfaces import MultiModalEmbeddings
12 from vllm.model_executor.models.utils import extract_layer_index
13 from vllm.multimodal.cache import processor_only_cache_from_config
@@ -23,24 +23,29 @@ class MultiModalBudget:
23
24 def __init__(
25 self,
26 - model_config: ModelConfig,
26 + renderer_config: RendererConfig,
27 scheduler_config: SchedulerConfig,
28 mm_registry: MultiModalRegistry,
29 ) -> None:
30 super().__init__()
31
32 - self.model_config = model_config
32 + self.renderer_config = renderer_config
33 + self.model_config = renderer_config.model_config
34 self.scheduler_config = scheduler_config
35 self.mm_registry = mm_registry
35 - self.cache = cache = processor_only_cache_from_config(model_config, mm_registry)
36 + self.cache = cache = processor_only_cache_from_config(
37 + renderer_config, mm_registry
38 + )
39
37 - self.max_model_len = model_config.max_model_len
40 + self.max_model_len = self.model_config.max_model_len
41 self.max_num_reqs = scheduler_config.max_num_seqs
42
40 - self.mm_limits = mm_registry.get_mm_limits_per_prompt(model_config, cache=cache)
43 + self.mm_limits = mm_registry.get_mm_limits_per_prompt(
44 + renderer_config, cache=cache
45 + )
46
47 max_tokens_by_modality = mm_registry.get_max_tokens_per_item_by_modality(
43 - model_config,
48 + renderer_config,
49 cache=cache,
50 profiler_limits=self.mm_limits,
51 )