| import uuid | |
| import math | |
| import asyncio | |
| from vllm.engine.arg_utils import AsyncEngineArgs | |
| from vllm.engine.async_llm_engine import AsyncLLMEngine | |
| from vllm.sampling_params import SamplingParams | |
| from transformers import AutoTokenizer | |
| from typing import List | |
| from contextlib import contextmanager | |
| import logging | |
| logger = logging.getLogger("vllm.engine.async_llm_engine").setLevel(logging.WARNING) | |
| class LLM: | |
| def __init__( | |
| self, | |
| model_name_or_path: str = 'meta-llama/Llama-3.2-1B-Instruct', | |
| temperature=0.0, | |
| top_p=1.0, | |
| logprobs=None, | |
| max_tokens=128, | |
| dtype='half', | |
| gpu_memory_utilization=0.9, | |
| num_gpus=1, | |
| max_model_len=10240, | |
| **kwargs | |
| ): | |
| print(f"Unused kwargs: {kwargs}") | |
| """ | |
| # AMPERE GPU: dtype='float16', enable_prefix_caching=True | |
| # VOLTA GPU: dtype='float32', enable_prefix_caching=True | |
| """ | |
| args = AsyncEngineArgs( | |
| model=model_name_or_path, | |
| dtype=dtype, | |
| tensor_parallel_size=num_gpus, | |
| gpu_memory_utilization=gpu_memory_utilization, | |
| max_model_len=max_model_len, | |
| ) | |
| self.model = AsyncLLMEngine.from_engine_args(AsyncEngineArgs.from_cli_args(args)) | |
| self.sampling_params = SamplingParams( | |
| temperature=temperature, | |
| top_p=top_p, | |
| logprobs=logprobs, | |
| skip_special_tokens=False, | |
| min_tokens=1, | |
| max_tokens=max_tokens, | |
| ) | |
| try: | |
| self.loop = asyncio.get_running_loop() | |
| except RuntimeError: | |
| self.loop = asyncio.new_event_loop() | |
| asyncio.set_event_loop(self.loop) | |
| self.tokenizer = AutoTokenizer.from_pretrained(model_name_or_path) | |
| if logprobs: | |
| self.set_classification() | |
| # TODO: Set the id_tokens as dynamic based on window size | |
| def set_classification(self, | |
| yes_strings=[' Yes', 'Yes', ' yes', 'yes', 'YES', ' YES'], | |
| no_strings=[' No', 'No', ' no', 'no', 'NO', ' NO'], | |
| id_strings=[chr(i) for i in range(65, 91)], | |
| max_rating=5, | |
| target_ratings=[1,2,3,4,5], | |
| ): | |
| self.id_tokens = [self.tokenizer.encode(item, add_special_tokens=False)[0] for item in id_strings] | |
| self.max_rating = max_rating | |
| self.target_ratings = target_ratings | |
| print(f"ID TOKENS: {self.id_tokens}") | |
| print(f"MAX RATING TOKEN: {self.max_rating} | TARGET TOKENS: {target_ratings}") | |
| def generate( | |
| self, | |
| prompts, | |
| binary_probs=False, | |
| dist_logp=False, | |
| rating_logp=False, | |
| expected_rating=False, | |
| ) -> List: | |
| if isinstance(prompts, str): | |
| prompts = [prompts] | |
| return self.loop.run_until_complete( | |
| self._agenerate(prompts, | |
| use_binary_probs=binary_probs, | |
| use_dist_probs=dist_logp, | |
| use_rating_logp=rating_logp, | |
| use_expected_rating=expected_rating) | |
| ) | |
| async def _iterate_over_output( | |
| self, | |
| output_collector, | |
| use_binary_probs=False, | |
| use_dist_probs=False, | |
| use_rating_logp=False, | |
| use_expected_rating=False, | |
| ) -> str: | |
| self.model._run_output_handler() | |
| finished = False | |
| while not finished: | |
| response = output_collector.get_nowait() or await output_collector.get() | |
| finished = response.finished | |
| if use_binary_probs: | |
| # TODO: make it more flexible. Instead of defining the yes no in the begining | |
| tok_item = response.outputs[0].logprobs[0] | |
| yes_ = math.exp(max( | |
| [-1e2] + [ | |
| item.logprob for tok, item in tok_item.items() | |
| if 'yes' in item.decoded_token.lower() | |
| ] | |
| )) | |
| no_ = math.exp(max( | |
| [-1e2] + [ | |
| item.logprob for tok, item in tok_item.items() | |
| if 'no' in item.decoded_token.lower() | |
| ] | |
| )) | |
| result = yes_ / (no_ + yes_) | |
| elif (use_rating_logp) or (use_expected_rating): | |
| tok_item = response.outputs[0].logprobs[0] | |
| rating_logp = [0.0 for _ in range(self.max_rating+1)] | |
| for topk, item in tok_item.items(): | |
| for r in range(self.max_rating+1): | |
| if str(r) in item.decoded_token: | |
| rating_logp[r] = max(math.exp(item.logprob), rating_logp[r]) | |
| if use_expected_rating: | |
| result = sum([r * rating_logp[r] for r in self.target_ratings]) / sum(rating_logp) | |
| else: | |
| target_ = sum([rating_logp[r] for r in self.target_ratings]) | |
| result = target_ / sum(rating_logp) | |
| # NOTE: the transformation is a bit hacky. | |
| # NOTE: make sure the numeric identifiers can also work | |
| elif use_dist_probs: | |
| tok_item = response.outputs[0].logprobs[0] | |
| min_logprob = min([item.logprob for item in tok_item.values()]) | |
| result = [min_logprob for _ in self.id_tokens] | |
| for topk, item in tok_item.items(): | |
| decoded_token = item.decoded_token.replace('[', '').replace(']', '') | |
| if len(decoded_token)==1 and (65 <= ord(decoded_token) <= 90): | |
| result[ord(decoded_token)-65] = max(item.logprob, result[ord(decoded_token)-65]) | |
| else: | |
| result = response.outputs[0].text | |
| return result | |
| async def _agenerate(self, prompts, **kwargs): | |
| request_ids = [str(uuid.uuid4()) for _ in prompts] | |
| # Add requests to the engine | |
| output_iterators = [ | |
| await self.model.add_request(request_id, prompt, self.sampling_params) | |
| for request_id, prompt in zip(request_ids, prompts) | |
| ] | |
| # Gather all the outputs | |
| outputs = await asyncio.gather(*[ | |
| self._iterate_over_output(output_iterator, **kwargs) | |
| for output_iterator in output_iterators | |
| ]) | |
| return list(outputs) | |
| def default(self): | |
| """ | |
| Usage example: | |
| with llm.default(): | |
| outputs = llm.generate(prompts) | |
| """ | |
| old_sampling_params = self.sampling_params | |
| try: | |
| print("Entering default sampling parameters context ...\nTemperature: 1.0, Top-p: 1.0, Max tokens: 512") | |
| self.sampling_params.temperature = 1.0 | |
| self.sampling_params.top_p = 1.0 | |
| self.sampling_params.max_tokens = 512 | |
| yield # This is where the code inside the 'with' block runs | |
| finally: | |
| self.sampling_params = old_sampling_params | |
Xet Storage Details
- Size:
- 7 kB
- Xet hash:
- 0fe2c947980ccd3aab8204dad245708853befdfbf86a3bc7fa8a45327587e4c9
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.