main
py 429 lines 13.7 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """WARNING: This test runs in both single-node (4 GPUs) and multi-node
4 (2 node with 2 GPUs each) modes. If the test only uses 2 GPUs, it is
5 important to set the distributed backend to "mp" to avoid Ray scheduling
6 all workers in a node other than the head node, which can cause the test
7 to fail.
8 """
9
10 import json
11 import os
12 from dataclasses import dataclass
13 from typing import Literal, NamedTuple
14
15 import pytest
16
17 from vllm.config.model import _FLOAT16_NOT_SUPPORTED_MODELS, RunnerOption
18 from vllm.logger import init_logger
19 from vllm.transformers_utils.config import get_config
20
21 from ..models.registry import HF_EXAMPLE_MODELS
22 from ..utils import compare_two_settings, create_new_process_for_each_test
23
24 logger = init_logger("test_pipeline_parallel")
25
26 VLLM_MULTI_NODE = os.getenv("VLLM_MULTI_NODE", "0") == "1"
27
28
29 class ParallelSetup(NamedTuple):
30 tp_size: int
31 pp_size: int
32 eager_mode: bool
33
34
35 class PPTestOptions(NamedTuple):
36 multi_node_only: bool
37 load_format: str | None = None
38
39
40 @dataclass
41 class PPTestSettings:
42 parallel_setups: list[ParallelSetup]
43 distributed_backends: list[str]
44 runner: RunnerOption
45 test_options: PPTestOptions
46
47 @staticmethod
48 def detailed(
49 *,
50 tp_base: int = 1,
51 pp_base: int = 2,
52 multi_node_only: bool = False,
53 runner: RunnerOption = "auto",
54 load_format: str | None = None,
55 ):
56 return PPTestSettings(
57 parallel_setups=[
58 ParallelSetup(tp_size=tp_base, pp_size=pp_base, eager_mode=False),
59 ParallelSetup(tp_size=tp_base, pp_size=2 * pp_base, eager_mode=False),
60 ParallelSetup(tp_size=tp_base, pp_size=2 * pp_base, eager_mode=True),
61 ParallelSetup(tp_size=2 * tp_base, pp_size=pp_base, eager_mode=False),
62 ParallelSetup(tp_size=2 * tp_base, pp_size=pp_base, eager_mode=True),
63 ],
64 distributed_backends=["mp", "ray"],
65 runner=runner,
66 test_options=PPTestOptions(
67 multi_node_only=multi_node_only, load_format=load_format
68 ),
69 )
70
71 @staticmethod
72 def fast(
73 *,
74 tp_base: int = 1,
75 pp_base: int = 2,
76 runner: RunnerOption = "auto",
77 multi_node_only: bool = False,
78 load_format: str | None = None,
79 ):
80 return PPTestSettings(
81 parallel_setups=[
82 ParallelSetup(tp_size=tp_base, pp_size=pp_base, eager_mode=True),
83 ],
84 distributed_backends=["mp"],
85 runner=runner,
86 test_options=PPTestOptions(
87 multi_node_only=multi_node_only, load_format=load_format
88 ),
89 )
90
91 def iter_params(self, model_id: str):
92 opts = self.test_options
93
94 for parallel_setup in self.parallel_setups:
95 for backend in self.distributed_backends:
96 yield (model_id, parallel_setup, backend, self.runner, opts)
97
98
99 # NOTE: You can adjust tp_base and/or pp_base locally to fit the model in GPU
100 # The values displayed here are only a rough indicator of the size of the model
101
102 TEXT_GENERATION_MODELS = {
103 # [Decoder-only]
104 "bigscience/bloomz-1b1": PPTestSettings.fast(),
105 "zai-org/chatglm3-6b": PPTestSettings.fast(),
106 "CohereLabs/c4ai-command-r-v01": PPTestSettings.fast(load_format="dummy"),
107 "databricks/dbrx-instruct": PPTestSettings.fast(load_format="dummy"),
108 "Deci/DeciLM-7B-instruct": PPTestSettings.fast(),
109 "deepseek-ai/deepseek-llm-7b-chat": PPTestSettings.fast(),
110 "deepseek-ai/DeepSeek-V2-Lite-Chat": PPTestSettings.fast(tp_base=2),
111 "LGAI-EXAONE/EXAONE-3.0-7.8B-Instruct": PPTestSettings.fast(),
112 "tiiuae/falcon-7b": PPTestSettings.fast(),
113 "google/gemma-1.1-2b-it": PPTestSettings.fast(),
114 "google/gemma-2-9b": PPTestSettings.fast(),
115 "openai-community/gpt2": PPTestSettings.fast(),
116 "EleutherAI/gpt-j-6b": PPTestSettings.fast(),
117 "EleutherAI/pythia-1.4b": PPTestSettings.fast(),
118 "ibm/PowerLM-3b": PPTestSettings.fast(),
119 "ibm/PowerMoE-3b": PPTestSettings.fast(),
120 "internlm/internlm2-chat-7b": PPTestSettings.fast(),
121 "ai21labs/Jamba-tiny-dev": PPTestSettings.fast(),
122 "pfnet/plamo-3-nict-2b-base": PPTestSettings.fast(),
123 "meta-llama/Llama-3.2-1B-Instruct": PPTestSettings.detailed(),
124 # Tests TransformersForCausalLM
125 "hmellor/Ilama-3.2-1B": PPTestSettings.fast(),
126 "openbmb/MiniCPM-2B-sft-bf16": PPTestSettings.fast(),
127 "openbmb/MiniCPM3-4B": PPTestSettings.fast(),
128 # Uses Llama
129 # "mistralai/Mistral-7B-Instruct-v0.1": PPTestSettings.fast(),
130 "state-spaces/mamba-130m-hf": PPTestSettings.fast(),
131 "mistralai/Mixtral-8x7B-Instruct-v0.1": PPTestSettings.fast(load_format="dummy"),
132 "nvidia/Minitron-8B-Base": PPTestSettings.fast(),
133 "allenai/OLMo-1B-hf": PPTestSettings.fast(),
134 "allenai/OLMo-2-0425-1B": PPTestSettings.fast(),
135 "allenai/OLMoE-1B-7B-0924-Instruct": PPTestSettings.fast(),
136 "facebook/opt-iml-max-1.3b": PPTestSettings.fast(),
137 "OrionStarAI/Orion-14B-Chat": PPTestSettings.fast(),
138 "microsoft/phi-2": PPTestSettings.fast(),
139 "microsoft/Phi-3-small-8k-instruct": PPTestSettings.fast(),
140 "microsoft/Phi-3.5-MoE-instruct": PPTestSettings.detailed(
141 multi_node_only=True, load_format="dummy"
142 ),
143 "Qwen/Qwen2.5-0.5B-Instruct": PPTestSettings.fast(),
144 "Qwen/Qwen1.5-MoE-A2.7B-Chat": PPTestSettings.fast(),
145 "stabilityai/stablelm-3b-4e1t": PPTestSettings.fast(),
146 "bigcode/starcoder2-3b": PPTestSettings.fast(),
147 "upstage/solar-pro-preview-instruct": PPTestSettings.fast(load_format="dummy"),
148 # [Encoder-only]
149 # TODO: Implement PP
150 # "facebook/bart-base": PPTestSettings.fast(),
151 }
152
153 EMBEDDING_MODELS = { # type: ignore[var-annotated]
154 # [Text-only]
155 "intfloat/e5-mistral-7b-instruct": PPTestSettings.fast(runner="pooling"),
156 "BAAI/bge-multilingual-gemma2": PPTestSettings.fast(runner="pooling"),
157 "Qwen/Qwen2.5-Math-RM-72B": PPTestSettings.fast(
158 load_format="dummy", runner="pooling"
159 ),
160 }
161
162 MULTIMODAL_MODELS = {
163 # [Decoder-only]
164 "Salesforce/blip2-opt-6.7b": PPTestSettings.fast(),
165 "zai-org/glm-4v-9b": PPTestSettings.fast(),
166 "OpenGVLab/InternVL3-1B": PPTestSettings.fast(),
167 "llava-hf/llava-1.5-7b-hf": PPTestSettings.fast(),
168 "llava-hf/llava-v1.6-mistral-7b-hf": PPTestSettings.fast(),
169 "llava-hf/LLaVA-NeXT-Video-7B-hf": PPTestSettings.fast(),
170 "llava-hf/llava-onevision-qwen2-0.5b-ov-hf": PPTestSettings.fast(),
171 "openbmb/MiniCPM-Llama3-V-2_5": PPTestSettings.fast(),
172 "allenai/Molmo-7B-D-0924": PPTestSettings.fast(),
173 "AIDC-AI/Ovis2-1B": PPTestSettings.fast(),
174 "AIDC-AI/Ovis2.5-2B": PPTestSettings.fast(),
175 "microsoft/Phi-3.5-vision-instruct": PPTestSettings.fast(),
176 "mistralai/Pixtral-12B-2409": PPTestSettings.fast(load_format="dummy"),
177 "Qwen/Qwen2-Audio-7B-Instruct": PPTestSettings.fast(),
178 "Qwen/Qwen2-VL-2B-Instruct": PPTestSettings.fast(),
179 "fixie-ai/ultravox-v0_5-llama-3_2-1b": PPTestSettings.fast(),
180 }
181
182 # NOTE: You can update this on your local machine to run specific tests
183 TEST_MODELS = [
184 # [LANGUAGE GENERATION]
185 "microsoft/Phi-3.5-MoE-instruct",
186 "meta-llama/Llama-3.2-1B-Instruct",
187 "hmellor/Ilama-3.2-1B",
188 "ibm/PowerLM-3b",
189 "deepseek-ai/DeepSeek-V2-Lite-Chat",
190 # [LANGUAGE EMBEDDING]
191 "intfloat/e5-mistral-7b-instruct",
192 "BAAI/bge-multilingual-gemma2",
193 # [MULTIMODAL GENERATION]
194 "OpenGVLab/InternVL3-1B",
195 "microsoft/Phi-3.5-vision-instruct",
196 "fixie-ai/ultravox-v0_5-llama-3_2-1b",
197 # [LANGUAGE GENERATION - HYBRID ARCH]
198 "ai21labs/Jamba-tiny-dev",
199 ]
200
201
202 def _compare_tp(
203 model_id: str,
204 parallel_setup: ParallelSetup,
205 distributed_backend: str,
206 runner: RunnerOption,
207 test_options: PPTestOptions,
208 num_gpus_available: int,
209 *,
210 method: Literal["generate", "encode"],
211 is_multimodal: bool,
212 ):
213 (
214 tp_size,
215 pp_size,
216 eager_mode,
217 ) = parallel_setup
218
219 multi_node_only, load_format = test_options
220
221 model_info = HF_EXAMPLE_MODELS.find_hf_info(model_id)
222 model_info.check_transformers_version(on_fail="skip")
223
224 trust_remote_code = model_info.trust_remote_code
225 tokenizer_mode = model_info.tokenizer_mode
226 hf_overrides = model_info.hf_overrides
227 hf_config = get_config(model_id, trust_remote_code)
228 require_embed_inputs = model_info.require_embed_inputs
229 max_num_seqs = model_info.max_num_seqs
230 enable_prefix_caching = model_info.enable_prefix_caching
231
232 dtype = "float16"
233 if hf_config.model_type in _FLOAT16_NOT_SUPPORTED_MODELS:
234 dtype = "bfloat16"
235
236 if load_format == "dummy":
237 # Avoid OOM
238 text_overrides = {
239 "num_hidden_layers": 4,
240 "hidden_size": 512,
241 "intermediate_size": 800,
242 "num_attention_heads": 4,
243 "num_key_value_heads": 1,
244 }
245
246 if is_multimodal:
247 hf_overrides.update({"text_config": text_overrides})
248 else:
249 hf_overrides.update(text_overrides)
250 else:
251 model_info.check_available_online(on_fail="skip")
252
253 if num_gpus_available < tp_size * pp_size:
254 pytest.skip(f"Need at least {tp_size} x {pp_size} GPUs")
255 if VLLM_MULTI_NODE and distributed_backend == "mp":
256 pytest.skip(
257 "Skipping multi-node pipeline parallel test for "
258 "multiprocessing distributed backend"
259 )
260 if multi_node_only and not VLLM_MULTI_NODE:
261 pytest.skip("Not in multi-node setting")
262
263 common_args = [
264 # use half precision for speed and memory savings in CI environment
265 "--dtype",
266 dtype,
267 "--max-model-len",
268 "2048",
269 "--max-num-seqs",
270 "8",
271 ]
272 if eager_mode:
273 common_args.append("--enforce-eager")
274 if runner != "auto":
275 common_args.extend(["--runner", runner])
276 if trust_remote_code:
277 common_args.append("--trust-remote-code")
278 if tokenizer_mode:
279 common_args.extend(["--tokenizer-mode", tokenizer_mode])
280 if load_format:
281 common_args.extend(["--load-format", load_format])
282 if hf_overrides:
283 common_args.extend(["--hf-overrides", json.dumps(hf_overrides)])
284 if not enable_prefix_caching:
285 common_args.append("--no-enable-prefix-caching")
286 if require_embed_inputs:
287 common_args.extend(
288 [
289 "--skip-tokenizer-init",
290 "--enable-prompt-embeds",
291 "--enable-mm-embeds",
292 ]
293 )
294 if max_num_seqs:
295 common_args.extend(["--max-num-seqs", f"{max_num_seqs}"])
296
297 if distributed_backend == "ray":
298 # Test Ray Compiled Graph for all the tests
299 pp_env = {
300 "VLLM_USE_RAY_COMPILED_DAG_NCCL_CHANNEL": "1",
301 }
302 elif distributed_backend == "mp":
303 pp_env = None
304 else:
305 pp_env = None
306
307 tp_env = None
308
309 pp_args = [
310 *common_args,
311 "--pipeline-parallel-size",
312 str(pp_size),
313 "--tensor-parallel-size",
314 str(tp_size),
315 "--distributed-executor-backend",
316 distributed_backend,
317 ]
318
319 # compare without pipeline parallelism
320 # NOTE: use mp backend for TP
321 # PP tests might involve multiple nodes, and ray might
322 # schedule all workers in a node other than the head node,
323 # which can cause the test to fail.
324 tp_args = [
325 *common_args,
326 "--tensor-parallel-size",
327 str(tp_size),
328 "--distributed-executor-backend",
329 "mp",
330 ]
331
332 compare_two_settings(
333 model_id,
334 pp_args,
335 tp_args,
336 pp_env,
337 tp_env,
338 method=method,
339 )
340
341
342 @pytest.mark.parametrize(
343 ("model_id", "parallel_setup", "distributed_backend", "runner", "test_options"),
344 [
345 params
346 for model_id, settings in TEXT_GENERATION_MODELS.items()
347 for params in settings.iter_params(model_id)
348 if model_id in TEST_MODELS
349 ],
350 )
351 @create_new_process_for_each_test()
352 def test_tp_language_generation(
353 model_id: str,
354 parallel_setup: ParallelSetup,
355 distributed_backend: str,
356 runner: RunnerOption,
357 test_options: PPTestOptions,
358 num_gpus_available,
359 ):
360 _compare_tp(
361 model_id,
362 parallel_setup,
363 distributed_backend,
364 runner,
365 test_options,
366 num_gpus_available,
367 method="generate",
368 is_multimodal=False,
369 )
370
371
372 @pytest.mark.parametrize(
373 ("model_id", "parallel_setup", "distributed_backend", "runner", "test_options"),
374 [
375 params
376 for model_id, settings in EMBEDDING_MODELS.items()
377 for params in settings.iter_params(model_id)
378 if model_id in TEST_MODELS
379 ],
380 )
381 @create_new_process_for_each_test()
382 def test_tp_language_embedding(
383 model_id: str,
384 parallel_setup: ParallelSetup,
385 distributed_backend: str,
386 runner: RunnerOption,
387 test_options: PPTestOptions,
388 num_gpus_available,
389 ):
390 _compare_tp(
391 model_id,
392 parallel_setup,
393 distributed_backend,
394 runner,
395 test_options,
396 num_gpus_available,
397 method="encode",
398 is_multimodal=False,
399 )
400
401
402 @pytest.mark.parametrize(
403 ("model_id", "parallel_setup", "distributed_backend", "runner", "test_options"),
404 [
405 params
406 for model_id, settings in MULTIMODAL_MODELS.items()
407 for params in settings.iter_params(model_id)
408 if model_id in TEST_MODELS
409 ],
410 )
411 @create_new_process_for_each_test()
412 def test_tp_multimodal_generation(
413 model_id: str,
414 parallel_setup: ParallelSetup,
415 distributed_backend: str,
416 runner: RunnerOption,
417 test_options: PPTestOptions,
418 num_gpus_available,
419 ):
420 _compare_tp(
421 model_id,
422 parallel_setup,
423 distributed_backend,
424 runner,
425 test_options,
426 num_gpus_available,
427 method="generate",
428 is_multimodal=True,
429 )