main
py 134 lines 4.17 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """This script contains:
4 1. test lora with speculative decoding for batch inference
5 """
6
7 import pytest
8 import torch
9
10 import vllm.envs as envs
11 from vllm import SamplingParams
12 from vllm.config import CompilationConfig
13 from vllm.lora.request import LoRARequest
14 from vllm.platforms import current_platform
15 from vllm.utils.torch_utils import set_random_seed
16
17 from ..utils import assert_request_outputs_match
18
19 LORA_TEST_PROMPT_MAP: dict[str, str] = {}
20
21 LORA_TEST_PROMPT_MAP["premjatin/qwen-linear-algebra-coder"] = """
22 ### INSTRUCTION:
23 You are an AI assistant that generates Python code to solve linear
24 algebra problems.
25
26 ### PROBLEM:
27 Find the eigenvalues and eigenvectors of the following 3x3 matrix:
28 [[3, 2, 0],
29 [2, 3, 0],
30 [0, 0, 2]]
31
32 ### OUTPUT FORMAT (STRICT):
33 Numbers should be represented as integers only.
34
35 ### PYTHON SOLUTION:
36 """
37
38 SEED = 42
39
40
41 @pytest.mark.parametrize(
42 "model_setup",
43 [
44 (
45 "eagle3",
46 "Qwen/Qwen3-1.7B",
47 "AngelSlim/Qwen3-1.7B_eagle3",
48 "premjatin/qwen-linear-algebra-coder",
49 1,
50 )
51 ],
52 )
53 @pytest.mark.skipif(
54 not current_platform.is_cuda_alike(), reason="Requires CUDA or ROCm"
55 )
56 def test_batch_inference_correctness(
57 monkeypatch: pytest.MonkeyPatch,
58 model_setup: tuple[str, str, str, str, int],
59 vllm_runner,
60 ):
61 """Compare the outputs of a LLM with only Lora and a LLM with both SD and Lora.
62 Should be the same and no failure when doing batch inference.
63 model_setup: (method, model_name, spec_model_name, lora_path, tp_size)
64 """
65 with monkeypatch.context() as m:
66 m.setenv("VLLM_BATCH_INVARIANT", "1")
67 m.setattr(envs, "VLLM_BATCH_INVARIANT", True)
68 set_random_seed(SEED)
69 m.setattr(torch.backends.cudnn, "benchmark", False)
70 m.setattr(torch.backends.cudnn, "deterministic", True)
71
72 method, model_name, spec_model_name, lora_path, tp_size = model_setup
73
74 prompts = [LORA_TEST_PROMPT_MAP[lora_path]] * 100
75 lora_request = LoRARequest("adapter", 1, lora_path)
76 sampling_params = SamplingParams(
77 temperature=0.0, top_p=1.0, top_k=-1, seed=SEED, max_tokens=128
78 )
79
80 # without speculative decoding
81 with vllm_runner(
82 model_name,
83 block_size=None,
84 trust_remote_code=True,
85 tensor_parallel_size=tp_size,
86 max_model_len=2048,
87 max_num_seqs=4,
88 enable_lora=True,
89 max_loras=1,
90 max_cpu_loras=1,
91 max_lora_rank=16,
92 enable_chunked_prefill=None,
93 compilation_config=CompilationConfig(),
94 ) as ref_runner:
95 ref_outputs = ref_runner.llm.generate(
96 prompts, sampling_params, lora_request=lora_request
97 )
98
99 with vllm_runner(
100 model_name,
101 block_size=None,
102 trust_remote_code=True,
103 tensor_parallel_size=tp_size,
104 speculative_config={
105 "method": method,
106 "model": spec_model_name,
107 "num_speculative_tokens": 3,
108 "max_model_len": 2048,
109 },
110 max_model_len=2048,
111 max_num_seqs=4,
112 enable_lora=True,
113 max_loras=1,
114 max_cpu_loras=1,
115 max_lora_rank=16,
116 enable_chunked_prefill=None,
117 compilation_config=CompilationConfig(),
118 ) as spec_runner:
119 lora_spec_outputs = spec_runner.llm.generate(
120 prompts, sampling_params, lora_request=lora_request
121 )
122
123 # Under greedy verification, the spec-decode output should equal the
124 # non-spec output (modulo FP noise from the target's verify-path matmul
125 # running at seqlen num_speculative_tokens+1 vs 1). 90% leaves slack.
126 assert_request_outputs_match(
127 ref_outputs,
128 lora_spec_outputs,
129 required_matches=int(0.90 * len(ref_outputs)) + 1,
130 context=(
131 f"LoRA + {method}: target={model_name}, draft={spec_model_name}, "
132 f"adapter={lora_path}"
133 ),
134 )