| |
| |
|
|
| """This example demonstrates instantiating vLLM with a custom logits processor |
| class object. |
| |
| For a basic example of implementing a custom logits processor, see |
| the `DummyLogitsProcessor` implementation in `vllm/test_utils.py`. |
| |
| For testing purposes, a dummy logits processor is employed which, if |
| `target_token` is passed as a keyword argument to `SamplingParams.extra_args`, |
| will mask out all tokens except `target_token`. |
| |
| A batch is constructed with `temperature=0.0` and 50% of requests specifying |
| `target_token`, and for these requests - and *only* these requests - we |
| expect the `target_token` to be decoded in each step, yielding an output |
| similar to that shown below: |
| |
| Generated Outputs: |
| ------------------------------------------------------------ |
| Prompt: 'Hello, my name is' |
| Output: " ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '" |
| ------------------------------------------------------------ |
| Prompt: 'The president of the United States is' |
| Output: " not a racist. He is a racist.\nHe's a racist because he" |
| ------------------------------------------------------------ |
| Prompt: 'The capital of France is' |
| Output: ' also also also also also also also also also also also also also |
| also also also' |
| ------------------------------------------------------------ |
| Prompt: 'The future of AI is' |
| Output: ' in the hands of the people.\n\nThe future of AI is in the' |
| ------------------------------------------------------------ |
| """ |
|
|
| from typing import Any |
|
|
| import torch |
|
|
| from vllm import LLM, SamplingParams |
| from vllm.config import VllmConfig |
| from vllm.v1.sample.logits_processor import ( |
| BatchUpdate, |
| LogitsProcessor, |
| ) |
| from vllm.v1.sample.logits_processor.builtin import process_dict_updates |
|
|
|
|
| |
| class DummyLogitsProcessor(LogitsProcessor): |
| """Fake logit processor to support unit testing and examples""" |
|
|
| @classmethod |
| def validate_params(cls, params: SamplingParams): |
| target_token: Any | None = params.extra_args and params.extra_args.get( |
| "target_token" |
| ) |
| if target_token is not None and not isinstance(target_token, int): |
| raise ValueError( |
| f"target_token value {target_token} {type(target_token)} is not int" |
| ) |
|
|
| def __init__( |
| self, vllm_config: VllmConfig, device: torch.device, is_pin_memory: bool |
| ): |
| self.req_info: dict[int, int] = {} |
|
|
| def is_argmax_invariant(self) -> bool: |
| return False |
|
|
| def update_state(self, batch_update: BatchUpdate | None): |
| def extract_extra_arg(params: SamplingParams) -> int | None: |
| self.validate_params(params) |
| return params.extra_args and params.extra_args.get("target_token") |
|
|
| process_dict_updates( |
| self.req_info, |
| batch_update, |
| |
| |
| |
| lambda params, _, __: extract_extra_arg(params), |
| ) |
|
|
| def apply(self, logits: torch.Tensor) -> torch.Tensor: |
| if not self.req_info: |
| return logits |
|
|
| |
| cols = torch.tensor( |
| list(self.req_info.values()), dtype=torch.long, device=logits.device |
| ) |
| rows = torch.tensor( |
| list(self.req_info.keys()), dtype=torch.long, device=logits.device |
| ) |
| values_to_keep = logits[rows, cols].clone() |
|
|
| |
| logits[rows] = float("-inf") |
| logits[rows, cols] = values_to_keep |
|
|
| return logits |
|
|
|
|
| |
| prompts = [ |
| "Hello, my name is", |
| "The president of the United States is", |
| "The capital of France is", |
| "The future of AI is", |
| ] |
| |
| sampling_params_list = [ |
| SamplingParams(temperature=0.0, extra_args={"target_token": 128}), |
| SamplingParams(temperature=0.0), |
| SamplingParams(temperature=0.0, extra_args={"target_token": 67}), |
| SamplingParams(temperature=0.0), |
| ] |
|
|
|
|
| def main(): |
| |
| llm = LLM( |
| model="facebook/opt-125m", |
| logits_processors=[DummyLogitsProcessor], |
| ) |
| |
| |
| |
| outputs = llm.generate(prompts, sampling_params_list) |
| |
| print("\nGenerated Outputs:\n" + "-" * 60) |
| for output in outputs: |
| prompt = output.prompt |
| generated_text = output.outputs[0].text |
| print(f"Prompt: {prompt!r}") |
| print(f"Output: {generated_text!r}") |
| print("-" * 60) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|