| # Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| import json | |
| import logging | |
| import requests | |
| import torch | |
| from typing import Dict, List, Optional | |
| class HuggingFaceModel: | |
| def __init__(self, name_or_path: str, **generation_kwargs) -> None: | |
| from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline | |
| self.tokenizer = AutoTokenizer.from_pretrained(name_or_path, trust_remote_code=True) | |
| if 'Yarn-Llama' in name_or_path: | |
| model_kwargs = None | |
| else: | |
| model_kwargs = {"attn_implementation": "flash_attention_2"} | |
| try: | |
| self.pipeline = pipeline( | |
| "text-generation", | |
| model=name_or_path, | |
| tokenizer=self.tokenizer, | |
| trust_remote_code=True, | |
| device_map="auto", | |
| torch_dtype=torch.bfloat16, | |
| model_kwargs=model_kwargs, | |
| ) | |
| except: | |
| self.pipeline = None | |
| self.model = AutoModelForCausalLM.from_pretrained(name_or_path, trust_remote_code=True, device_map="auto", torch_dtype=torch.bfloat16,) | |
| self.generation_kwargs = generation_kwargs | |
| self.stop = self.generation_kwargs.pop('stop') | |
| if self.tokenizer.pad_token is None: | |
| # add pad token to allow batching (known issue for llama2) | |
| self.tokenizer.padding_side = 'left' | |
| self.tokenizer.pad_token = self.tokenizer.eos_token | |
| self.tokenizer.pad_token_id = self.tokenizer.eos_token_id | |
| def __call__(self, prompt: str, **kwargs) -> dict: | |
| return self.process_batch([prompt], **kwargs)[0] | |
| def process_batch(self, prompts: List[str], **kwargs) -> List[dict]: | |
| if self.pipeline is None: | |
| inputs = self.tokenizer(prompts, return_tensors="pt", padding=True).to(self.model.device) | |
| generated_ids = self.model.generate( | |
| **inputs, | |
| **self.generation_kwargs | |
| ) | |
| generated_texts = self.tokenizer.batch_decode(generated_ids, skip_special_tokens=True) | |
| else: | |
| output = self.pipeline(text_inputs=prompts, **self.generation_kwargs, ) | |
| assert len(output) == len(prompts) | |
| # output in the form of a list of list of dictionaries | |
| # outer list len = batch size | |
| # inner list len = 1 | |
| generated_texts = [llm_result[0]["generated_text"] for llm_result in output] | |
| results = [] | |
| for text, prompt in zip(generated_texts, prompts): | |
| # remove the input form the generated text | |
| # This is a workaround for the llama3 tokenizer not being able to reproduce the same prompt after tokenization | |
| # see Issue https://github.com/NVIDIA/RULER/issues/54 for explaination | |
| if self.pipeline is None: | |
| tokenized_prompt = self.tokenizer(prompt, return_tensors="pt", padding=True) | |
| prompt = self.tokenizer.decode(tokenized_prompt.input_ids[0], skip_special_tokens=True) | |
| if text.startswith(prompt): | |
| text = text[len(prompt):] | |
| if self.stop is not None: | |
| for s in self.stop: | |
| text = text.split(s)[0] | |
| results.append({'text': [text]}) | |
| return results | |
| class MambaModel: | |
| def __init__(self, name_or_path: str, **generation_kwargs) -> None: | |
| from transformers import AutoTokenizer | |
| from mamba_ssm.models.mixer_seq_simple import MambaLMHeadModel | |
| self.tokenizer = AutoTokenizer.from_pretrained("EleutherAI/gpt-neox-20b") | |
| self.device = "cuda" | |
| self.model = MambaLMHeadModel.from_pretrained(name_or_path, device=self.device, dtype=torch.bfloat16) | |
| self.generation_kwargs = generation_kwargs | |
| self.stop = self.generation_kwargs.pop('stop') | |
| self.max_genlen = self.generation_kwargs.pop('max_new_tokens') | |
| self.minp = 0.0 | |
| def __call__(self, prompt: str, **kwargs) -> Dict[str, List[str]]: | |
| # tokenize | |
| tokens = self.tokenizer(prompt, return_tensors="pt") | |
| input_ids = tokens.input_ids.to(self.device) | |
| max_length = input_ids.shape[1] + self.max_genlen | |
| # generate | |
| out = self.model.generate( | |
| input_ids=input_ids, | |
| max_length=max_length, | |
| cg=True, | |
| return_dict_in_generate=True, | |
| output_scores=True, | |
| enable_timing=False, | |
| **self.generation_kwargs, | |
| ) | |
| assert len(out.sequences) == 1 | |
| # detok | |
| return {'text': [self.tokenizer.decode(out.sequences[0][input_ids.shape[1]:])]} | |
| def process_batch(self, prompts: List[str], **kwargs) -> List[dict]: | |
| # FIXME: naive implementation | |
| return [self.__call__(prompt, **kwargs) for prompt in prompts] | |
Xet Storage Details
- Size:
- 5.4 kB
- Xet hash:
- 8f32664f46692c5c57ad0c151f71d2757373db403a213a34e3c9457c76d34eb2
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.