guia-idem-api / core /correctifier.py
RafelSV's picture
Upload 4 files
6f7871e verified
Raw
History Blame Contribute Delete
8.23 kB
import time
import numpy as np
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM, AutoProcessor
from transformers import Gemma3ForConditionalGeneration
import langdetect
from langdetect import detect
from langdetect import DetectorFactory
from pathlib import Path
import datetime
from core.prompts import prompts
DetectorFactory.seed = 0
available_models = {"LLAMA1B": "meta-llama/Llama-3.2-1B-Instruct",
"GEMMA2B": "google/gemma-2-2b-it",
"SALAMANDRA2B": "BSC-LT/salamandra-2b-instruct",
"LLAMA3B": "meta-llama/Llama-3.2-3B-Instruct",
"GEMMA4B": "google/gemma-3-4b-it",
"OLMO7B": "allenai/OLMo-2-1124-7B-Instruct",
"SALAMANDRA7B": "BSC-LT/salamandra-7b-instruct",
"LLAMA8B": "meta-llama/Llama-3.1-8B-Instruct",
"GEMMA9B": "google/gemma-2-9b-it",
"GEMMA12B": "google/gemma-3-12b-it",
"GEMMA27B": "google/gemma-3-27b-it"}
# Inspired with https://huggingface.co/google/gemma-3-12b-it
# More info in https://huggingface.co/docs/transformers/main/en/model_doc/gemma3
class Correctifier(object):
def __init__(self, selected_model, access_token, device, lang="en"):
self.lang = lang
pretrained_model = available_models[selected_model]
self.pretrained_model = pretrained_model
self.tokenizer = AutoTokenizer.from_pretrained(pretrained_model, token=access_token)
self.processor = AutoProcessor.from_pretrained(pretrained_model, token=access_token)
# If CUDA device is chosen and more than one available, use all
device_map = "auto" if device.type == 'cuda' and torch.cuda.is_available() and torch.cuda.device_count() > 1 else device
print("Using {} device".format(device_map), device.type, torch.cuda.is_available(), torch.cuda.device_count())
if pretrained_model.startswith('google/gemma-3'):
self.model = Gemma3ForConditionalGeneration.from_pretrained(pretrained_model, token=access_token,
torch_dtype=torch.bfloat16,
device_map=device_map).eval()
elif pretrained_model.startswith('google/gemma-2'):
self.model = Gemma3ForConditionalGeneration.from_pretrained(pretrained_model, token=access_token,
torch_dtype=torch.float16,
device_map=device_map).eval()
else:
self.model = AutoModelForCausalLM.from_pretrained(pretrained_model, torch_dtype=torch.bfloat16,
token=access_token,
device_map=device_map).eval()
self.model.generation_config.pad_token_id = self.tokenizer.eos_token_id
self.device = device
print("Model loaded.")
if torch.cuda.is_available():
for i in range(torch.cuda.device_count()):
print("Device " + str(i) + ' : ' + torch.cuda.get_device_properties(i).name)
print("Total memory: " + str(torch.cuda.get_device_properties(i).total_memory))
print("Reserved: " + str(torch.cuda.memory_reserved(i)))
print("Allocated: " + str(torch.cuda.memory_allocated(i)))
print("Model on GPU: " + str(round(100 * np.sum([param.is_cuda for param in self.model.parameters()]) / len(
list(self.model.parameters())))) + "%")
def correct(self, sentence, force_prompt=None, force_raw_output=False):
# print("Simplifying:\n" + sentence)
new_tokens = 1000
# Prompt based on https://aclanthology.org/2023.emnlp-main.821/
if force_prompt is not None:
prompt = force_prompt
else:
prompt = prompts[self.lang]
prompt += "\nINPUT:\n" + sentence # + "\nOUTPUT:\n"
messages = [
# {"role": "system","content": [{"type": "text", "text": "You are a helpful assistant."}] },
{
"role": "user",
"content": [{"type": "text", "text": prompt}]
}
]
if self.pretrained_model.startswith("allenai/OLMo"):
inputs = self.tokenizer([prompt], return_tensors='pt', return_token_type_ids=False)
elif self.pretrained_model.startswith("BSC-LT/salamandra"):
prompt_w_templ = [{"role": "user", "content": prompt}]
messages = self.tokenizer.apply_chat_template(
prompt_w_templ,
tokenize=False,
add_generation_prompt=True,
)
inputs = self.tokenizer.encode(messages, add_special_tokens=False, return_tensors="pt")
else:
inputs = self.processor.apply_chat_template(messages, add_generation_prompt=True, tokenize=True,
return_dict=True,
return_tensors="pt")
if self.pretrained_model.startswith("google/gemma-3"):
inputs = inputs.to(self.device, dtype=torch.bfloat16)
elif self.pretrained_model.startswith("google/gemma-2"):
inputs = inputs.to(self.device, dtype=torch.float16)
else:
inputs = inputs.to(self.device)
if self.pretrained_model.startswith("BSC-LT/salamandra"):
input_len = 0
print(inputs.shape)
input_len = inputs.shape[-1]
else:
input_len = inputs["input_ids"].shape[-1]
start = time.time()
if self.pretrained_model.startswith("BSC-LT/salamandra"):
with torch.inference_mode():
# generation = self.model.generate(input_ids=inputs.to(self.device), max_new_tokens=200)
generation = self.model.generate(input_ids=inputs, max_new_tokens=200, do_sample=False, top_p=None,
temperature=None)
generation = generation[0][input_len:]
else:
with torch.inference_mode():
# Using greedy decoding, see others in https://huggingface.co/docs/transformers/en/generation_strategies
generation = self.model.generate(**inputs, max_new_tokens=new_tokens, do_sample=False, top_p=None,
temperature=None)
generation = generation[0][input_len:]
end = time.time()
evaluate_time = end - start
print("Response time: " + str(evaluate_time))
output_text = self.processor.decode(generation, skip_special_tokens=True)
# print(output_text)
if force_raw_output:
return output_text
else:
return self.parse_responses(sentence, output_text)
def parse_responses(self, sentence, output_text):
response = output_text # [output_text.find('OUTPUT:\n'):]
# for end_marker in ["<eos>", "<|eot_id|>", "```<|end_of_text|>", "<end_of_turn>", "<|endoftext|>"]:
# if response.endswith(end_marker):
# response = response[0:(-(len(end_marker)))]
responses = response.split("\n")
responses = [response for response in responses if not (
response.strip() in ['', 'OUTPUT:', 'INPUT:', sentence] or response.startswith(
'Rephrasing ') or response.startswith('Here are ') or response.startswith('Rewrite '))]
responses = [response.lstrip('1234567890-').lstrip('.').lstrip() for response in responses]
if (Path(langdetect.__file__).parents[0] / 'profiles' / self.lang).exists():
responses = [response for response in responses if len(response) < 10 or detect(response) == self.lang]
if len(responses) > 0:
return responses[0]
else:
return ''