main
py 220 lines 6.93 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """This example shows how to use FlexKV with vLLM for prefix caching.
4
5 FlexKV is a distributed KV Store and multi-level cache management system for
6 ultra-large-scale LLM inference.
7
8 Requirements:
9 - Install FlexKV (https://github.com/taco-project/FlexKV):
10 1. git clone git@github.com:taco-project/FlexKV.git
11 2. cd FlexKV && bash build.sh
12 - Ensure FlexKV is compatible with your vLLM version.
13
14 Usage:
15 1. Run this script:
16 python examples/disaggregated/flexkv_connector/prefix_caching_flexkv.py \
17 --model /path/to/your/model
18
19 2. Arguments:
20 --model Path or name of the model (required)
21 --tp-size Tensor parallel size (default: 1)
22 --gpu-memory-util GPU memory utilization (default: 0.4)
23
24 3. The script will:
25 - Create a FlexKV configuration file.
26 - Set the FLEXKV_CONFIG_PATH environment variable.
27 - Run vLLM with FlexKVConnectorV1 enabled.
28 - Compare results between regular execution, vLLM's default prefix
29 caching, and FlexKV.
30 """
31
32 import argparse
33 import json
34 import os
35 import time
36
37 from vllm import LLM, SamplingParams
38 from vllm.distributed import cleanup_dist_env_and_memory
39
40 # NOTE: This is just a running example. For benchmarking purpose,
41 # please see benchmarks/benchmark_prefix_caching.py
42
43
44 def parse_args():
45 parser = argparse.ArgumentParser(
46 description="Example of using FlexKV with vLLM for prefix caching."
47 )
48 parser.add_argument(
49 "--model",
50 type=str,
51 required=True,
52 help="Path or name of the model to use.",
53 )
54 parser.add_argument(
55 "--tp-size",
56 type=int,
57 default=1,
58 help="Tensor parallel size (default: 1).",
59 )
60 parser.add_argument(
61 "--gpu-memory-util",
62 type=float,
63 default=0.4,
64 help="GPU memory utilization fraction (default: 0.4).",
65 )
66 return parser.parse_args()
67
68
69 def main():
70 args = parse_args()
71
72 flexkv_config = {
73 "server_recv_port": f"ipc:///tmp/flexkv_test_{os.getpid()}",
74 "cache_config": {
75 "enable_cpu": True,
76 "num_cpu_blocks": 10240,
77 },
78 "num_log_interval_requests": 200,
79 }
80 flexkv_config_path = f"./flexkv_config_{os.getpid()}.json"
81 with open(flexkv_config_path, "w") as f:
82 json.dump(flexkv_config, f)
83 os.environ["FLEXKV_CONFIG_PATH"] = flexkv_config_path
84
85 try:
86 _run(args)
87 finally:
88 if os.path.exists(flexkv_config_path):
89 os.remove(flexkv_config_path)
90
91
92 def _run(args):
93 # Common prefix.
94 prefix = (
95 "You are an expert school principal, skilled in effectively managing "
96 "faculty and staff. Draft 10-15 questions for a potential first grade "
97 "Head Teacher for my K-12, all-girls', independent school that emphasizes "
98 "community, joyful discovery, and life-long learning. The candidate is "
99 "coming in for a first-round panel interview for a 8th grade Math "
100 "teaching role. They have 5 years of previous teaching experience "
101 "as an assistant teacher at a co-ed, public school with experience "
102 "in middle school math teaching. Based on these information, fulfill "
103 "the following paragraph: "
104 )
105
106 # Sample prompts.
107 prompts = [
108 "Hello, my name is",
109 "The president of the United States is",
110 "The capital of France is",
111 "The future of AI is",
112 ]
113
114 generating_prompts = [prefix + prompt for prompt in prompts]
115
116 # Create a sampling params object.
117 sampling_params = SamplingParams(temperature=0.0)
118
119 kv_transfer_config = {
120 "kv_connector": "FlexKVConnectorV1",
121 "kv_role": "kv_both",
122 }
123
124 # Create an LLM without prefix caching as a baseline.
125 regular_llm = LLM(
126 model=args.model,
127 enable_prefix_caching=False,
128 gpu_memory_utilization=args.gpu_memory_util,
129 tensor_parallel_size=args.tp_size,
130 )
131
132 print("Results without `enable_prefix_caching`")
133
134 # ruff: noqa: E501
135 # Generate texts from the prompts. The output is a list of RequestOutput
136 # objects that contain the prompt, generated text, and other information.
137 outputs = regular_llm.generate(generating_prompts, sampling_params)
138
139 regular_generated_texts = []
140 # Print the outputs.
141 print("-" * 50)
142 for output in outputs:
143 prompt = output.prompt
144 generated_text = output.outputs[0].text
145 regular_generated_texts.append(generated_text)
146 print(f"Prompt: {prompt!r}\nGenerated text: {generated_text!r}")
147 print("-" * 50)
148
149 # Destroy the LLM object and free up the GPU memory.
150 del regular_llm
151 cleanup_dist_env_and_memory()
152
153 # Create an LLM with prefix caching enabled.
154 prefix_cached_llm = LLM(
155 model=args.model,
156 enable_prefix_caching=True,
157 gpu_memory_utilization=args.gpu_memory_util,
158 tensor_parallel_size=args.tp_size,
159 kv_transfer_config=kv_transfer_config,
160 )
161
162 # Warmup so that the shared prompt's KV cache is computed.
163 prefix_cached_llm.generate(generating_prompts[0], sampling_params)
164
165 # wait for offload kv task finished.
166 time.sleep(2)
167
168 # Generate with prefix caching.
169 outputs = prefix_cached_llm.generate(generating_prompts, sampling_params)
170
171 print("Results with `enable_prefix_caching`")
172
173 cached_generated_texts = []
174 # Print the outputs. You should see the same outputs as before.
175 print("-" * 50)
176 for output in outputs:
177 prompt = output.prompt
178 generated_text = output.outputs[0].text
179 cached_generated_texts.append(generated_text)
180 print(f"Prompt: {prompt!r}\nGenerated text: {generated_text!r}")
181 print("-" * 50)
182
183 # Compare the results and display the speedup
184 generated_same = all(
185 regular_generated_texts[i] == cached_generated_texts[i]
186 for i in range(len(prompts))
187 )
188 print(f"Generated answers are the same: {generated_same}")
189
190 # wait for offload kv task finished.
191 time.sleep(2)
192
193 # reset prefix cache to use flexkv
194 prefix_cached_llm.reset_prefix_cache()
195
196 # Generate with prefix caching.
197 outputs = prefix_cached_llm.generate(generating_prompts, sampling_params)
198
199 print("Results with `flexkv`")
200
201 flexkv_generated_texts = []
202 # Print the outputs. You should see the same outputs as before.
203 print("-" * 50)
204 for output in outputs:
205 prompt = output.prompt
206 generated_text = output.outputs[0].text
207 flexkv_generated_texts.append(generated_text)
208 print(f"Prompt: {prompt!r}\nGenerated text: {generated_text!r}")
209 print("-" * 50)
210
211 # Compare the results and display the speedup
212 generated_same = all(
213 regular_generated_texts[i] == flexkv_generated_texts[i]
214 for i in range(len(prompts))
215 )
216 print(f"Generated answers are the same: {generated_same}")
217
218
219 if __name__ == "__main__":
220 main()