A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 15, 19:45 UTC
[Feature] Add visionarena offline support for benchmark_throughput (#14654)
Signed-off-by: Jennifer Zhao <7443418+JenZhao@users.noreply.github.com> Signed-off-by: Jennifer Zhao <ai.jenniferzhao@gmail.com> Co-authored-by: Jennifer Zhao <7443418+JenZhao@users.noreply.github.com> Co-authored-by: Jennifer Zhao <JenZhao@users.noreply.github.com> Co-authored-by: Roger Wang <136131678+ywang96@users.noreply.github.com>
Jennifer Zhao committed
Mar 13, 2025 at 21:07 UTC
a6e0d096dd48d1190fb548dd81fdd31f310391e3
3 files changed
+291
-99
benchmarks/README.md
+47
-11
@@ -43,20 +43,26 @@ become available.
43
<tr>
44
<td><strong>HuggingFace</strong></td>
45
<td style="text-align: center;">✅</td>
46
- <td style="text-align: center;">🚧</td>
46
+ <td style="text-align: center;">🟡</td>
47
<td>Specify your dataset path on HuggingFace</td>
48
</tr>
49
<tr>
50
<td><strong>VisionArena</strong></td>
51
<td style="text-align: center;">✅</td>
52
- <td style="text-align: center;">🚧</td>
52
+ <td style="text-align: center;">✅</td>
53
<td><code>lmarena-ai/vision-arena-bench-v0.1</code> (a HuggingFace dataset)</td>
54
</tr>
55
</tbody>
56
</table>
57
-✅: supported
57
+
58
+✅: supported
59
+
60
🚧: to be supported
61
62
+🟡: Partial support. Currently, HuggingFaceDataset only supports dataset formats
63
+similar to `lmms-lab/LLaVA-OneVision-Data`. If you need support for other dataset
64
+formats, please consider contributing.
65
+
66
**Note**: VisionArena’s `dataset-name` should be set to `hf`
67
68
---
@@ -79,7 +85,7 @@ NUM_PROMPTS=10
85
BACKEND="openai-chat"
86
DATASET_NAME="sharegpt"
87
DATASET_PATH="<your data path>/ShareGPT_V3_unfiltered_cleaned_split.json"
82
-python3 benchmarks/benchmark_serving.py --backend ${BACKEND} --model ${MODEL_NAME} --endpoint /v1/chat/completions --dataset-name ${DATASET_NAME} --dataset-path ${DATASET_PATH} --num-prompts ${NUM_PROMPTS}
88
+python3 vllm/benchmarks/benchmark_serving.py --backend ${BACKEND} --model ${MODEL_NAME} --endpoint /v1/chat/completions --dataset-name ${DATASET_NAME} --dataset-path ${DATASET_PATH} --num-prompts ${NUM_PROMPTS}
89
```
90
91
If successful, you will see the following output
@@ -123,7 +129,7 @@ DATASET_NAME="hf"
129
DATASET_PATH="lmarena-ai/vision-arena-bench-v0.1"
130
DATASET_SPLIT='train'
131
126
-python3 benchmarks/benchmark_serving.py \
132
+python3 vllm/benchmarks/benchmark_serving.py \
133
--backend "${BACKEND}" \
134
--model "${MODEL_NAME}" \
135
--endpoint "/v1/chat/completions" \
@@ -140,35 +146,65 @@ python3 benchmarks/benchmark_serving.py \
146
MODEL_NAME="NousResearch/Hermes-3-Llama-3.1-8B"
147
NUM_PROMPTS=10
148
DATASET_NAME="sonnet"
143
-DATASET_PATH="benchmarks/sonnet.txt"
149
+DATASET_PATH="vllm/benchmarks/sonnet.txt"
150
145
-python3 benchmarks/benchmark_throughput.py \
151
+python3 vllm/benchmarks/benchmark_throughput.py \
152
--model "${MODEL_NAME}" \
153
--dataset-name "${DATASET_NAME}" \
154
--dataset-path "${DATASET_PATH}" \
155
--num-prompts "${NUM_PROMPTS}"
150
- ```
156
+```
157
158
If successful, you will see the following output
159
160
```
155
-Throughput: 7.35 requests/s, 4789.20 total tokens/s, 1102.83 output tokens/s
161
+Throughput: 7.15 requests/s, 4656.00 total tokens/s, 1072.15 output tokens/s
162
+Total num prompt tokens: 5014
163
+Total num output tokens: 1500
164
+```
165
+
166
+### VisionArena Benchmark for Vision Language Models
167
+
168
+``` bash
169
+MODEL_NAME="Qwen/Qwen2-VL-7B-Instruct"
170
+NUM_PROMPTS=10
171
+DATASET_NAME="hf"
172
+DATASET_PATH="lmarena-ai/vision-arena-bench-v0.1"
173
+DATASET_SPLIT="train"
174
+
175
+python3 vllm/benchmarks/benchmark_throughput.py \
176
+ --model "${MODEL_NAME}" \
177
+ --backend "vllm-chat" \
178
+ --dataset-name "${DATASET_NAME}" \
179
+ --dataset-path "${DATASET_PATH}" \
180
+ --num-prompts "${NUM_PROMPTS}" \
181
+ --hf-split "${DATASET_SPLIT}"
182
+```
183
+
184
+The `num prompt tokens` now includes image token counts
185
+
186
+```
187
+Throughput: 2.55 requests/s, 4036.92 total tokens/s, 326.90 output tokens/s
188
+Total num prompt tokens: 14527
189
+Total num output tokens: 1280
190
```
191
192
### Benchmark with LoRA Adapters
193
194
``` bash
195
+# download dataset
196
+# wget https://huggingface.co/datasets/anon8231489123/ShareGPT_Vicuna_unfiltered/resolve/main/ShareGPT_V3_unfiltered_cleaned_split.json
197
MODEL_NAME="meta-llama/Llama-2-7b-hf"
198
BACKEND="vllm"
199
DATASET_NAME="sharegpt"
164
-DATASET_PATH="/home/jovyan/data/vllm_benchmark_datasets/ShareGPT_V3_unfiltered_cleaned_split.json"
200
+DATASET_PATH="<your data path>/ShareGPT_V3_unfiltered_cleaned_split.json"
201
NUM_PROMPTS=10
202
MAX_LORAS=2
203
MAX_LORA_RANK=8
204
ENABLE_LORA="--enable-lora"
205
LORA_PATH="yard1/llama-2-7b-sql-lora-test"
206
171
-python3 benchmarks/benchmark_throughput.py \
207
+python3 vllm/benchmarks/benchmark_throughput.py \
208
--model "${MODEL_NAME}" \
209
--backend "${BACKEND}" \
210
--dataset_path "${DATASET_PATH}" \
benchmarks/benchmark_dataset.py
+43
-22
@@ -46,7 +46,7 @@ class SampleRequest:
46
Represents a single inference request for benchmarking.
47
"""
48
49
- prompt: str
49
+ prompt: Union[str, Any]
50
prompt_len: int
51
expected_output_len: int
52
multi_modal_data: Optional[Union[MultiModalDataDict, dict]] = None
@@ -84,6 +84,20 @@ class BenchmarkDataset(ABC):
84
if random_seed is not None else self.DEFAULT_SEED)
85
self.data = None
86
87
+ def apply_multimodal_chat_transformation(
88
+ self,
89
+ prompt: str,
90
+ mm_content: Optional[MultiModalDataDict] = None) -> list[dict]:
91
+ """
92
+ Transform a prompt and optional multimodal content into a chat format.
93
+ This method is used for chat models that expect a specific
94
+ conversation format.
95
+ """
96
+ content = [{"text": prompt, "type": "text"}]
97
+ if mm_content is not None:
98
+ content.append(mm_content)
99
+ return [{"role": "user", "content": content}]
100
+
101
def load_data(self) -> None:
102
"""
103
Load data from the dataset path into self.data.
@@ -338,6 +352,7 @@ class ShareGPTDataset(BenchmarkDataset):
352
lora_path: Optional[str] = None,
353
max_loras: Optional[int] = None,
354
output_len: Optional[int] = None,
355
+ enable_multimodal_chat: bool = False,
356
**kwargs) -> list:
357
samples: list = []
358
for entry in self.data:
@@ -358,6 +373,9 @@ class ShareGPTDataset(BenchmarkDataset):
373
skip_min_output_len_check=output_len
374
is not None):
375
continue
376
+ if enable_multimodal_chat:
377
+ prompt = self.apply_multimodal_chat_transformation(
378
+ prompt, None)
379
samples.append(
380
SampleRequest(
381
prompt=prompt,
@@ -550,10 +568,13 @@ class HuggingFaceDataset(BenchmarkDataset):
568
split=self.dataset_split,
569
streaming=True,
570
)
553
-
554
- if "conversations" not in self.data.features:
555
- raise ValueError("HF Dataset must have a 'conversations' column.")
556
-
571
+ if self.data.features is None or "conversations" \
572
+ not in self.data.features:
573
+ raise ValueError(
574
+ "HuggingFaceDataset currently only supports datasets with "
575
+ "a 'conversations' column like lmms-lab/LLaVA-OneVision-Data. "
576
+ "Please consider contributing if you would like to add "
577
+ "support for additional dataset formats.")
578
# Shuffle and filter examples with at least 2 conversations.
579
self.data = self.data.shuffle(seed=self.random_seed).filter(
580
lambda x: len(x["conversations"]) >= 2)
@@ -561,9 +582,8 @@ class HuggingFaceDataset(BenchmarkDataset):
582
def sample(self,
583
tokenizer: PreTrainedTokenizerBase,
584
num_requests: int,
564
- lora_path: Optional[str] = None,
565
- max_loras: Optional[int] = None,
585
output_len: Optional[int] = None,
586
+ enable_multimodal_chat: bool = False,
587
**kwargs) -> list:
588
sampled_requests = []
589
dynamic_output = output_len is None
@@ -571,13 +591,9 @@ class HuggingFaceDataset(BenchmarkDataset):
591
for item in self.data:
592
if len(sampled_requests) >= num_requests:
593
break
574
-
594
conv = item["conversations"]
595
prompt, completion = conv[0]["value"], conv[1]["value"]
596
578
- lora_request, tokenizer = self.get_random_lora_request(
579
- tokenizer, lora_path=lora_path, max_loras=max_loras)
580
-
597
prompt_ids = tokenizer(prompt).input_ids
598
completion_ids = tokenizer(completion).input_ids
599
prompt_len = len(prompt_ids)
@@ -587,16 +603,20 @@ class HuggingFaceDataset(BenchmarkDataset):
603
if dynamic_output and not is_valid_sequence(
604
prompt_len, completion_len):
605
continue
590
-
606
mm_content = process_image(
607
item["image"]) if "image" in item else None
608
+ if enable_multimodal_chat:
609
+ # Note: when chat is enabled the request prompt_len is no longer
610
+ # accurate and we will be using request output to count the
611
+ # actual prompt len and output len
612
+ prompt = self.apply_multimodal_chat_transformation(
613
+ prompt, mm_content)
614
sampled_requests.append(
615
SampleRequest(
616
prompt=prompt,
617
prompt_len=prompt_len,
618
expected_output_len=output_len,
619
multi_modal_data=mm_content,
599
- lora_request=lora_request,
620
))
621
return sampled_requests
622
@@ -606,7 +626,7 @@ class HuggingFaceDataset(BenchmarkDataset):
626
# -----------------------------------------------------------------------------
627
628
609
-class VisionArenaDataset(BenchmarkDataset):
629
+class VisionArenaDataset(HuggingFaceDataset):
630
"""
631
Vision Arena Dataset.
632
"""
@@ -617,14 +637,9 @@ class VisionArenaDataset(BenchmarkDataset):
637
638
def __init__(
639
self,
620
- dataset_split: str,
621
- dataset_subset: Optional[str] = None,
640
**kwargs,
641
) -> None:
642
super().__init__(**kwargs)
625
- self.dataset_split = dataset_split
626
- self.dataset_subset = dataset_subset
627
-
643
if self.dataset_path != self.VISION_ARENA_DATASET_PATH:
644
raise ValueError(f"Only support Vision Arena dataset.\
645
This data path {self.dataset_path} is not valid.")
@@ -645,9 +660,9 @@ class VisionArenaDataset(BenchmarkDataset):
660
def sample(self,
661
tokenizer: PreTrainedTokenizerBase,
662
num_requests: int,
648
- output_len: int = DEFAULT_OUTPUT_LEN,
663
+ output_len: Optional[int] = None,
664
+ enable_multimodal_chat: bool = False,
665
**kwargs) -> list:
650
- # TODO (jenniferzhao): Add support for offline benchmark sampling
666
output_len = (output_len
667
if output_len is not None else self.DEFAULT_OUTPUT_LEN)
668
sampled_requests = []
@@ -655,8 +670,14 @@ class VisionArenaDataset(BenchmarkDataset):
670
if len(sampled_requests) >= num_requests:
671
break
672
prompt = item["turns"][0][0]["content"]
658
- prompt_len = len(tokenizer(prompt).input_ids)
673
mm_content = process_image(item["images"][0])
674
+ prompt_len = len(tokenizer(prompt).input_ids)
675
+ if enable_multimodal_chat:
676
+ # Note: when chat is enabled the request prompt_len is no longer
677
+ # accurate and we will be using request output to count the
678
+ # actual prompt len
679
+ prompt = self.apply_multimodal_chat_transformation(
680
+ prompt, mm_content)
681
sampled_requests.append(
682
SampleRequest(
683
prompt=prompt,
benchmarks/benchmark_throughput.py
+201
-66
@@ -11,8 +11,9 @@ from typing import Any, Optional, Union
11
12
import torch
13
import uvloop
14
-from benchmark_dataset import (BurstGPTDataset, RandomDataset, SampleRequest,
15
- ShareGPTDataset, SonnetDataset)
14
+from benchmark_dataset import (BurstGPTDataset, HuggingFaceDataset,
15
+ RandomDataset, SampleRequest, ShareGPTDataset,
16
+ SonnetDataset, VisionArenaDataset)
17
from benchmark_utils import convert_to_pytorch_benchmark_format, write_to_json
18
from tqdm import tqdm
19
from transformers import (AutoModelForCausalLM, AutoTokenizer,
@@ -23,6 +24,7 @@ from vllm.entrypoints.openai.api_server import (
24
build_async_engine_client_from_engine_args)
25
from vllm.inputs import TextPrompt, TokensPrompt
26
from vllm.lora.request import LoRARequest
27
+from vllm.outputs import RequestOutput
28
from vllm.sampling_params import BeamSearchParams
29
from vllm.utils import FlexibleArgumentParser, merge_async_iterators
30
@@ -32,7 +34,7 @@ def run_vllm(
34
n: int,
35
engine_args: EngineArgs,
36
disable_detokenize: bool = False,
35
-) -> float:
37
+) -> tuple[float, Optional[list[RequestOutput]]]:
38
from vllm import LLM, SamplingParams
39
llm = LLM(**dataclasses.asdict(engine_args))
40
assert all(
@@ -66,12 +68,13 @@ def run_vllm(
68
69
use_beam_search = False
70
71
+ outputs = None
72
if not use_beam_search:
73
start = time.perf_counter()
71
- llm.generate(prompts,
72
- sampling_params,
73
- lora_request=lora_requests,
74
- use_tqdm=True)
74
+ outputs = llm.generate(prompts,
75
+ sampling_params,
76
+ lora_request=lora_requests,
77
+ use_tqdm=True)
78
end = time.perf_counter()
79
else:
80
assert lora_requests is None, "BeamSearch API does not support LoRA"
@@ -89,7 +92,46 @@ def run_vllm(
92
ignore_eos=True,
93
))
94
end = time.perf_counter()
92
- return end - start
95
+ return end - start, outputs
96
+
97
+
98
+def run_vllm_chat(
99
+ requests: list[SampleRequest],
100
+ n: int,
101
+ engine_args: EngineArgs,
102
+ disable_detokenize: bool = False) -> tuple[float, list[RequestOutput]]:
103
+ """
104
+ Run vLLM chat benchmark. This function is recommended ONLY for benchmarking
105
+ multimodal models as it properly handles multimodal inputs and chat
106
+ formatting. For non-multimodal models, use run_vllm() instead.
107
+ """
108
+ from vllm import LLM, SamplingParams
109
+ llm = LLM(**dataclasses.asdict(engine_args))
110
+
111
+ assert all(
112
+ llm.llm_engine.model_config.max_model_len >= (
113
+ request.prompt_len + request.expected_output_len)
114
+ for request in requests), (
115
+ "Please ensure that max_model_len is greater than the sum of "
116
+ "prompt_len and expected_output_len for all requests.")
117
+
118
+ prompts = []
119
+ sampling_params: list[SamplingParams] = []
120
+ for request in requests:
121
+ prompts.append(request.prompt)
122
+ sampling_params.append(
123
+ SamplingParams(
124
+ n=n,
125
+ temperature=1.0,
126
+ top_p=1.0,
127
+ ignore_eos=True,
128
+ max_tokens=request.expected_output_len,
129
+ detokenize=not disable_detokenize,
130
+ ))
131
+ start = time.perf_counter()
132
+ outputs = llm.chat(prompts, sampling_params, use_tqdm=True)
133
+ end = time.perf_counter()
134
+ return end - start, outputs
135
136
137
async def run_vllm_async(
@@ -264,6 +306,8 @@ def get_requests(args, tokenizer):
306
dataset_cls = RandomDataset
307
elif args.dataset_name == "sharegpt":
308
dataset_cls = ShareGPTDataset
309
+ if args.backend == "vllm-chat":
310
+ sample_kwargs["enable_multimodal_chat"] = True
311
elif args.dataset_name == "sonnet":
312
assert tokenizer.chat_template or tokenizer.default_chat_template, (
313
"Tokenizer/model must have chat template for sonnet dataset.")
@@ -272,6 +316,19 @@ def get_requests(args, tokenizer):
316
sample_kwargs["return_prompt_formatted"] = True
317
elif args.dataset_name == "burstgpt":
318
dataset_cls = BurstGPTDataset
319
+ elif args.dataset_name == "hf":
320
+ if args.backend != "vllm-chat":
321
+ raise ValueError(
322
+ "hf datasets only are supported by vllm-chat backend")
323
+ # Choose between VisionArenaDataset and HuggingFaceDataset based on
324
+ # provided parameters.
325
+ dataset_cls = (VisionArenaDataset if args.dataset_path
326
+ == VisionArenaDataset.VISION_ARENA_DATASET_PATH
327
+ and args.hf_subset is None else HuggingFaceDataset)
328
+ common_kwargs['dataset_subset'] = args.hf_subset
329
+ common_kwargs['dataset_split'] = args.hf_split
330
+ sample_kwargs["enable_multimodal_chat"] = True
331
+
332
else:
333
raise ValueError(f"Unknown dataset name: {args.dataset_name}")
334
# Remove None values
@@ -290,6 +347,7 @@ def main(args: argparse.Namespace):
347
requests = get_requests(args, tokenizer)
348
is_multi_modal = any(request.multi_modal_data is not None
349
for request in requests)
350
+ request_outputs: Optional[list[RequestOutput]] = None
351
if args.backend == "vllm":
352
if args.async_engine:
353
elapsed_time = uvloop.run(
@@ -301,9 +359,9 @@ def main(args: argparse.Namespace):
359
args.disable_detokenize,
360
))
361
else:
304
- elapsed_time = run_vllm(requests, args.n,
305
- EngineArgs.from_cli_args(args),
306
- args.disable_detokenize)
362
+ elapsed_time, request_outputs = run_vllm(
363
+ requests, args.n, EngineArgs.from_cli_args(args),
364
+ args.disable_detokenize)
365
elif args.backend == "hf":
366
assert args.tensor_parallel_size == 1
367
elapsed_time = run_hf(requests, args.model, tokenizer, args.n,
@@ -312,20 +370,45 @@ def main(args: argparse.Namespace):
370
elif args.backend == "mii":
371
elapsed_time = run_mii(requests, args.model, args.tensor_parallel_size,
372
args.output_len)
373
+ elif args.backend == "vllm-chat":
374
+ elapsed_time, request_outputs = run_vllm_chat(
375
+ requests, args.n, EngineArgs.from_cli_args(args),
376
+ args.disable_detokenize)
377
else:
378
raise ValueError(f"Unknown backend: {args.backend}")
317
- total_num_tokens = sum(request.prompt_len + request.expected_output_len
318
- for request in requests)
319
- total_output_tokens = sum(request.expected_output_len
320
- for request in requests)
321
- if is_multi_modal:
322
- print("\033[91mWARNING\033[0m: Multi-modal request detected. The "
379
+
380
+ if request_outputs:
381
+ # Note: with the vllm and vllm-chat backends,
382
+ # we have request_outputs, which we use to count tokens.
383
+ total_prompt_tokens = 0
384
+ total_output_tokens = 0
385
+ for ro in request_outputs:
386
+ if not isinstance(ro, RequestOutput):
387
+ continue
388
+ total_prompt_tokens += len(
389
+ ro.prompt_token_ids) if ro.prompt_token_ids else 0
390
+ total_output_tokens += sum(
391
+ len(o.token_ids) for o in ro.outputs if o)
392
+ total_num_tokens = total_prompt_tokens + total_output_tokens
393
+ else:
394
+ total_num_tokens = sum(r.prompt_len + r.expected_output_len
395
+ for r in requests)
396
+ total_output_tokens = sum(r.expected_output_len for r in requests)
397
+ total_prompt_tokens = total_num_tokens - total_output_tokens
398
+
399
+ if is_multi_modal and args.backend != "vllm-chat":
400
+ print("\033[91mWARNING\033[0m: Multi-modal request with "
401
+ f"{args.backend} backend detected. The "
402
"following metrics are not accurate because image tokens are not"
403
" counted. See vllm-project/vllm/issues/9778 for details.")
404
# TODO(vllm-project/vllm/issues/9778): Count multi-modal token length.
405
+ # vllm-chat backend counts the image tokens now
406
+
407
print(f"Throughput: {len(requests) / elapsed_time:.2f} requests/s, "
408
f"{total_num_tokens / elapsed_time:.2f} total tokens/s, "
409
f"{total_output_tokens / elapsed_time:.2f} output tokens/s")
410
+ print(f"Total num prompt tokens: {total_prompt_tokens}")
411
+ print(f"Total num output tokens: {total_output_tokens}")
412
413
# Output JSON results if specified
414
if args.output_json:
@@ -341,17 +424,100 @@ def main(args: argparse.Namespace):
424
save_to_pytorch_benchmark_format(args, results)
425
426
427
+def validate_args(args):
428
+ """
429
+ Validate command-line arguments.
430
+ """
431
+
432
+ # === Deprecation and Defaulting ===
433
+ if args.dataset is not None:
434
+ warnings.warn(
435
+ "The '--dataset' argument will be deprecated in the next release. "
436
+ "Please use '--dataset-name' and '--dataset-path' instead.",
437
+ stacklevel=2)
438
+ args.dataset_path = args.dataset
439
+
440
+ if not getattr(args, "tokenizer", None):
441
+ args.tokenizer = args.model
442
+
443
+ # === Backend Validation ===
444
+ valid_backends = {"vllm", "hf", "mii", "vllm-chat"}
445
+ if args.backend not in valid_backends:
446
+ raise ValueError(f"Unsupported backend: {args.backend}")
447
+
448
+ # === Dataset Configuration ===
449
+ if not args.dataset and not args.dataset_path:
450
+ print(
451
+ "When dataset path is not set, it will default to random dataset")
452
+ args.dataset_name = 'random'
453
+ if args.input_len is None:
454
+ raise ValueError("input_len must be provided for a random dataset")
455
+
456
+ # === Dataset Name Specific Checks ===
457
+ # --hf-subset and --hf-split: only used
458
+ # when dataset_name is 'hf'
459
+ if args.dataset_name != "hf" and (
460
+ getattr(args, "hf_subset", None) is not None
461
+ or getattr(args, "hf_split", None) is not None):
462
+ warnings.warn("--hf-subset and --hf-split will be ignored \
463
+ since --dataset-name is not 'hf'.",
464
+ stacklevel=2)
465
+ elif args.dataset_name == "hf" and args.backend != "vllm-chat":
466
+ raise ValueError(
467
+ "When --dataset-name is 'hf', backend must be 'vllm-chat'")
468
+
469
+ # --random-range-ratio: only used when dataset_name is 'random'
470
+ if args.dataset_name != 'random' and args.random_range_ratio is not None:
471
+ warnings.warn("--random-range-ratio will be ignored since \
472
+ --dataset-name is not 'random'.",
473
+ stacklevel=2)
474
+
475
+ # --prefix-len: only used when dataset_name is 'random', 'sonnet', or not
476
+ # set.
477
+ if args.dataset_name not in {"random", "sonnet", None
478
+ } and args.prefix_len is not None:
479
+ warnings.warn("--prefix-len will be ignored since --dataset-name\
480
+ is not 'random', 'sonnet', or not set.",
481
+ stacklevel=2)
482
+
483
+ # === LoRA Settings ===
484
+ if getattr(args, "enable_lora", False) and args.backend != "vllm":
485
+ raise ValueError(
486
+ "LoRA benchmarking is only supported for vLLM backend")
487
+ if getattr(args, "enable_lora", False) and args.lora_path is None:
488
+ raise ValueError("LoRA path must be provided when enable_lora is True")
489
+
490
+ # === Backend-specific Validations ===
491
+ if args.backend == "hf" and args.hf_max_batch_size is None:
492
+ raise ValueError("HF max batch size is required for HF backend")
493
+ if args.backend != "hf" and args.hf_max_batch_size is not None:
494
+ raise ValueError("HF max batch size is only for HF backend.")
495
+
496
+ if args.backend in {"hf", "mii"} and getattr(args, "quantization",
497
+ None) is not None:
498
+ raise ValueError("Quantization is only for vLLM backend.")
499
+
500
+ if args.backend == "mii" and args.dtype != "auto":
501
+ raise ValueError("dtype must be auto for MII backend.")
502
+ if args.backend == "mii" and args.n != 1:
503
+ raise ValueError("n must be 1 for MII backend.")
504
+ if args.backend == "mii" and args.tokenizer != args.model:
505
+ raise ValueError(
506
+ "Tokenizer must be the same as the model for MII backend.")
507
+
508
+
509
if __name__ == "__main__":
510
parser = FlexibleArgumentParser(description="Benchmark the throughput.")
511
parser.add_argument("--backend",
512
type=str,
348
- choices=["vllm", "hf", "mii"],
513
+ choices=["vllm", "hf", "mii", "vllm-chat"],
514
default="vllm")
350
- parser.add_argument("--dataset-name",
351
- type=str,
352
- choices=["sharegpt", "random", "sonnet", "burstgpt"],
353
- help="Name of the dataset to benchmark on.",
354
- default="sharegpt")
515
+ parser.add_argument(
516
+ "--dataset-name",
517
+ type=str,
518
+ choices=["sharegpt", "random", "sonnet", "burstgpt", "hf"],
519
+ help="Name of the dataset to benchmark on.",
520
+ default="sharegpt")
521
parser.add_argument(
522
"--dataset",
523
type=str,
@@ -419,55 +585,24 @@ if __name__ == "__main__":
585
parser.add_argument(
586
"--random-range-ratio",
587
type=float,
422
- default=1.0,
588
+ default=None,
589
help="Range of sampled ratio of input/output length, "
590
"used only for RandomDataSet.",
591
)
592
593
+ # hf dtaset
594
+ parser.add_argument("--hf-subset",
595
+ type=str,
596
+ default=None,
597
+ help="Subset of the HF dataset.")
598
+ parser.add_argument("--hf-split",
599
+ type=str,
600
+ default=None,
601
+ help="Split of the HF dataset.")
602
+
603
parser = AsyncEngineArgs.add_cli_args(parser)
604
args = parser.parse_args()
605
if args.tokenizer is None:
606
args.tokenizer = args.model
431
- if args.dataset is not None:
432
- warnings.warn(
433
- "The '--dataset' argument will be deprecated in the next "
434
- "release. Please use '--dataset-name' and "
435
- "'--dataset-path' in the future runs.",
436
- stacklevel=2)
437
- args.dataset_path = args.dataset
438
- if args.dataset is None and args.dataset_path is None:
439
- # for random dataset, the default sampling setting is in
440
- # benchmark_dataset.RandomDataset
441
- print("When dataset is not set, it will default to random dataset")
442
- else:
443
- assert args.input_len is None
444
- if args.enable_lora:
445
- assert args.lora_path is not None
446
-
447
- if args.backend == "vllm":
448
- if args.hf_max_batch_size is not None:
449
- raise ValueError("HF max batch size is only for HF backend.")
450
- elif args.backend == "hf":
451
- if args.hf_max_batch_size is None:
452
- raise ValueError("HF max batch size is required for HF backend.")
453
- if args.quantization is not None:
454
- raise ValueError("Quantization is only for vLLM backend.")
455
- if args.enable_lora is not None:
456
- raise ValueError("LoRA benchmarking is only supported for vLLM"
457
- " backend")
458
- elif args.backend == "mii":
459
- if args.dtype != "auto":
460
- raise ValueError("dtype must be auto for MII backend.")
461
- if args.n != 1:
462
- raise ValueError("n must be 1 for MII backend.")
463
- if args.quantization is not None:
464
- raise ValueError("Quantization is only for vLLM backend.")
465
- if args.hf_max_batch_size is not None:
466
- raise ValueError("HF max batch size is only for HF backend.")
467
- if args.tokenizer != args.model:
468
- raise ValueError("Tokenizer must be the same as the model for MII "
469
- "backend.")
470
- if args.enable_lora is not None:
471
- raise ValueError("LoRA benchmarking is only supported for vLLM"
472
- " backend")
607
+ validate_args(args)
608
main(args)