main
py 165 lines 5.86 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 """This example demonstrates a special case of wrapping a request-level logits
5 processor, namely the case where it is necessary to utilize engine config or
6 environment info passed to the constructor. The subclass must override the
7 wrapper base class `__init__()` method to access the engine config, the device
8 identifier, or the flag which indicates whether pinned memory is available.
9
10 For demo purposes, a request-level dummy logits processor is employed which
11 causes the same token (`target_token`) to be decoded in each step. The
12 request-level dummy logits processor is wrapped to create a batch-level logits
13 processor, which can apply the logits processor to output logits from all
14 requests in the persistent batch in a given decode step.
15
16 The wrapped dummy logits processor below models a scenario where we must
17 disable the logits processor on non-"cuda" platforms. The wrapper base class
18 `__init__()` is overridden in order to check this condition and set a flag.
19
20 A batch is constructed with `temperature=0.0` and 50% of requests specifying
21 `target_token`, and for these requests - and *only* these requests - we
22 expect that on a "cuda" device the output will look something like:
23
24 Generated Outputs:
25 ------------------------------------------------------------
26 Prompt: 'Hello, my name is'
27 Output: " ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '"
28 ------------------------------------------------------------
29 Prompt: 'The president of the United States is'
30 Output: " not a racist. He is a racist.\nHe's a racist because he"
31 ------------------------------------------------------------
32 Prompt: 'The capital of France is'
33 Output: ' also also also also also also also also also also also also also
34 also also also'
35 ------------------------------------------------------------
36 Prompt: 'The future of AI is'
37 Output: ' in the hands of the people.\n\nThe future of AI is in the'
38 ------------------------------------------------------------
39
40 which indicates that the logits processor is running. However, on a non-"cuda"
41 device, the first and third requests would not repeat the same token.
42 """
43
44 import torch
45
46 from vllm import LLM, SamplingParams
47 from vllm.config import VllmConfig
48 from vllm.logger import init_logger
49 from vllm.v1.sample.logits_processor import (
50 AdapterLogitsProcessor,
51 RequestLogitsProcessor,
52 )
53
54 logger = init_logger(__name__)
55
56
57 class DummyPerReqLogitsProcessor:
58 """The request-level logits processor masks out all logits except the
59 token id identified by `target_token`"""
60
61 def __init__(self, target_token: int) -> None:
62 """Specify `target_token`."""
63 self.target_token = target_token
64
65 def __call__(
66 self,
67 output_ids: list[int],
68 logits: torch.Tensor,
69 ) -> torch.Tensor:
70 val_to_keep = logits[self.target_token].item()
71 logits[:] = float("-inf")
72 logits[self.target_token] = val_to_keep
73 return logits
74
75
76 class WrappedPerReqLogitsProcessor(AdapterLogitsProcessor):
77 """Example of overriding the wrapper class `__init__()` in order to utilize
78 info about the device type"""
79
80 @classmethod
81 def validate_params(cls, params: SamplingParams):
82 target_token = params.extra_args and params.extra_args.get("target_token")
83 if target_token is not None and not isinstance(target_token, int):
84 raise ValueError(
85 f"`target_token` has to be an integer, got {target_token}."
86 )
87
88 def __init__(
89 self, vllm_config: VllmConfig, device: torch.device, is_pin_memory: bool
90 ):
91 super().__init__(vllm_config, device, is_pin_memory)
92 self.is_cuda = device.type == "cuda"
93
94 def is_argmax_invariant(self) -> bool:
95 return False
96
97 def new_req_logits_processor(
98 self,
99 params: SamplingParams,
100 ) -> RequestLogitsProcessor | None:
101 """This method returns a new request-level logits processor, customized
102 to the `target_token` value associated with a particular request.
103
104 Returns None if the logits processor should not be applied to the
105 particular request. To use the logits processor the request must have
106 a "target_token" custom argument with an integer value, and the device
107 must be "cuda"-type
108
109 Args:
110 params: per-request sampling params
111
112 Returns:
113 `Callable` request logits processor, or None
114
115 """
116 if (
117 not self.is_cuda
118 or (
119 target_token := params.extra_args
120 and params.extra_args.get("target_token")
121 )
122 is None
123 ):
124 return None
125 return DummyPerReqLogitsProcessor(target_token)
126
127
128 # Sample prompts.
129 prompts = [
130 "Hello, my name is",
131 "The president of the United States is",
132 "The capital of France is",
133 "The future of AI is",
134 ]
135 # Create a mixture of requests which do and don't utilize the dummy logitproc
136 sampling_params_list = [
137 SamplingParams(temperature=0.0, extra_args={"target_token": 128}),
138 SamplingParams(temperature=0.0),
139 SamplingParams(temperature=0.0, extra_args={"target_token": 67}),
140 SamplingParams(temperature=0.0),
141 ]
142
143
144 def main():
145 # Create an LLM.
146 llm = LLM(
147 model="facebook/opt-125m",
148 logits_processors=[WrappedPerReqLogitsProcessor],
149 )
150 # Generate texts from the prompts.
151 # The output is a list of RequestOutput objects
152 # that contain the prompt, generated text, and other information.
153 outputs = llm.generate(prompts, sampling_params_list)
154 # Print the outputs.
155 print("\nGenerated Outputs:\n" + "-" * 60)
156 for output in outputs:
157 prompt = output.prompt
158 generated_text = output.outputs[0].text
159 print(f"Prompt: {prompt!r}")
160 print(f"Output: {generated_text!r}")
161 print("-" * 60)
162
163
164 if __name__ == "__main__":
165 main()