main
py 153 lines 5.33 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 """This example demonstrates wrapping a request-level logits processor to be
5 compatible with vLLM's batch-level logits processing
6
7 For demo purposes, a dummy logits processor is employed which, if
8 `target_token` is passed as a keyword argument to `SamplingParams.extra_args`,
9 will mask out all tokens except `target_token`. This logits processor can be
10 applied to a vector of logits associated with a single decode step for a single
11 request. The logits processor cannot be applied to a request which does not
12 pass in a `target_token` custom argument.
13
14 The request-level dummy logits processor is wrapped to create a batch-level
15 logits processor, which can apply the logits processor to output logits from
16 all requests in the persistent batch in a given decode step. For requests which
17 do not provide a `target_token` argument, the corresponding row of `logits`
18 will not be modified.
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 the `target_token` to be decoded in each step, yielding an output
23 similar to that shown below:
24
25 Generated Outputs:
26 ------------------------------------------------------------
27 Prompt: 'Hello, my name is'
28 Output: " ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '"
29 ------------------------------------------------------------
30 Prompt: 'The president of the United States is'
31 Output: " not a racist. He is a racist.\nHe's a racist because he"
32 ------------------------------------------------------------
33 Prompt: 'The capital of France is'
34 Output: ' also also also also also also also also also also also also also
35 also also also'
36 ------------------------------------------------------------
37 Prompt: 'The future of AI is'
38 Output: ' in the hands of the people.\n\nThe future of AI is in the'
39 ------------------------------------------------------------
40 """
41
42 from typing import Any
43
44 import torch
45
46 from vllm import LLM, SamplingParams
47 from vllm.logger import init_logger
48 from vllm.v1.sample.logits_processor import (
49 AdapterLogitsProcessor,
50 RequestLogitsProcessor,
51 )
52
53 logger = init_logger(__name__)
54
55
56 class DummyPerReqLogitsProcessor:
57 """The request-level logits processor masks out all logits except the
58 token id identified by `target_token`"""
59
60 def __init__(self, target_token: int) -> None:
61 """Specify `target_token`."""
62 self.target_token = target_token
63
64 def __call__(
65 self,
66 output_ids: list[int],
67 logits: torch.Tensor,
68 ) -> torch.Tensor:
69 val_to_keep = logits[self.target_token].item()
70 logits[:] = float("-inf")
71 logits[self.target_token] = val_to_keep
72 return logits
73
74
75 class WrappedPerReqLogitsProcessor(AdapterLogitsProcessor):
76 """Example of wrapping a fake request-level logit processor to create a
77 batch-level logits processor"""
78
79 @classmethod
80 def validate_params(cls, params: SamplingParams):
81 target_token: Any | None = params.extra_args and params.extra_args.get(
82 "target_token"
83 )
84 if target_token is not None and not isinstance(target_token, int):
85 raise ValueError(f"target_token value {target_token} is not int")
86
87 def is_argmax_invariant(self) -> bool:
88 return False
89
90 def new_req_logits_processor(
91 self,
92 params: SamplingParams,
93 ) -> RequestLogitsProcessor | None:
94 """This method returns a new request-level logits processor, customized
95 to the `target_token` value associated with a particular request.
96
97 Returns None if the logits processor should not be applied to the
98 particular request. To use the logits processor the request must have
99 a "target_token" custom argument with an integer value.
100
101 Args:
102 params: per-request sampling params
103
104 Returns:
105 `Callable` request logits processor, or None
106
107 """
108 target_token: Any | None = params.extra_args and params.extra_args.get(
109 "target_token"
110 )
111 if target_token is None:
112 return None
113 return DummyPerReqLogitsProcessor(target_token)
114
115
116 # Sample prompts.
117 prompts = [
118 "Hello, my name is",
119 "The president of the United States is",
120 "The capital of France is",
121 "The future of AI is",
122 ]
123 # Create a mixture of requests which do and don't utilize the dummy logitproc
124 sampling_params_list = [
125 SamplingParams(temperature=0.0, extra_args={"target_token": 128}),
126 SamplingParams(temperature=0.0),
127 SamplingParams(temperature=0.0, extra_args={"target_token": 67}),
128 SamplingParams(temperature=0.0),
129 ]
130
131
132 def main():
133 # Create an LLM.
134 llm = LLM(
135 model="facebook/opt-125m",
136 logits_processors=[WrappedPerReqLogitsProcessor],
137 )
138 # Generate texts from the prompts.
139 # The output is a list of RequestOutput objects
140 # that contain the prompt, generated text, and other information.
141 outputs = llm.generate(prompts, sampling_params_list)
142 # Print the outputs.
143 print("\nGenerated Outputs:\n" + "-" * 60)
144 for output in outputs:
145 prompt = output.prompt
146 generated_text = output.outputs[0].text
147 print(f"Prompt: {prompt!r}")
148 print(f"Output: {generated_text!r}")
149 print("-" * 60)
150
151
152 if __name__ == "__main__":
153 main()