Newer
Older
import torch.nn.functional as F
from transformers import AutoModelForCausalLM, AutoModel, AutoTokenizer
from transformers import GenerationConfig
import torch
import json
from torch import Tensor
from tqdm.auto import tqdm
import faiss
import numpy as np
from sentence_transformers import SentenceTransformer
from .base_model import ShopBenchBaseModel
# Set a consistent seed for reproducibility
A dummy model implementation for ShopBench, illustrating how to handle both
multiple choice and other types of tasks like Ranking, Retrieval, and Named Entity Recognition.
This model uses a consistent random seed for reproducible results.
"""Initializes the model and sets the random seed for consistency."""
def predict(self, prompt: str, is_multiple_choice: bool) -> str:
Generates a prediction based on the input prompt and task type.
For multiple choice tasks, it randomly selects a choice.
For other tasks, it returns a list of integers as a string,
representing the model's prediction in a format compatible with task-specific parsers.
Args:
prompt (str): The input prompt for the model.
is_multiple_choice (bool): Indicates whether the task is a multiple choice question.
Returns:
str: The prediction as a string representing a single integer[0, 3] for multiple choice tasks,
or a string representing a comma separated list of integers for Ranking, Retrieval tasks,
or a string representing a comma separated list of named entities for Named Entity Recognition tasks.
or a string representing the (unconstrained) generated response for the generation tasks
Please refer to parsers.py for more details on how these responses will be parsed by the evaluator.
# Randomly select one of the possible responses for multiple choice tasks
return str(random.choice(possible_responses))
# For other tasks, shuffle the possible responses and return as a string
random.shuffle(possible_responses)
return str(possible_responses)
# Note: As this is dummy model, we are returning random responses for non-multiple choice tasks.
# For generation tasks, this should ideally return an unconstrained string.
class llama3_8b_FewShot(ShopBenchBaseModel):
def __init__(self):
random.seed(AICROWD_RUN_SEED)
self.build_vector_database()
model_path = './models/Meta-Llama-3-8B-Instruct'
self.tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
self.model = AutoModelForCausalLM.from_pretrained(model_path, torch_dtype=torch.float16, device_map='auto', trust_remote_code=True)
self.system_prompt = "You are a helpful and multilingual online shopping assistant. You can understand and respond to user queries in English, German, Italian, French, Japanese, Spanish, Chinese. You are knowledgeable about various products. NOTE:ONLY OUTPUT THE ANSWER!!\n"
self.terminators = [
self.tokenizer.eos_token_id,
self.tokenizer.convert_tokens_to_ids("<|eot_id|>"),
# self.tokenizer.convert_tokens_to_ids("\\n"),
]
def get_detailed_instruct(self, task_description: str, query: str) -> str:
return f'Instruct: {task_description}\nQuery: {query}'
self.embed_model = SentenceTransformer("./models/multilingual-e5-large-instruct")
# few shot preprocess
dim = 1024 # Embedding dimension for intfloat/multilingual-e5-large
nlist = 1024 # Number of cluster centroids
quantizer = faiss.IndexFlatIP(dim)
self.index = faiss.IndexIVFFlat(quantizer, dim, nlist, faiss.METRIC_INNER_PRODUCT)
self.index.nprobe = 3
self.few_shot_example_text = []
self.fewshot_embeddings = []
with open('./models/sample_example1.jsonl','r',encoding='utf8') as f:
for i in f.readlines():
passage = ''
t_data = json.loads(i.strip())
if "input" in t_data:
passage = t_data['instruction'] + t_data['input'] + '\nOutput:' + str( t_data['output']) + '\n'
else:
passage = t_data['instruction'] + str(t_data['output']) + '\n'
passage = passage.replace('\\n','\n')
self.few_shot_example_text.append(passage)
# preprocess retriev index and save trained index
# self.fewshot_embeddings = self.embed_model.encode(self.few_shot_example_text, batch_size=128, show_progress_bar=True)
# print(f'process few shot example embedding done! {len(self.few_shot_example_text)}')
# self.index.train(self.fewshot_embeddings.astype(np.float32))
# self.index.add(self.fewshot_embeddings.astype(np.float32))
# faiss.write_index(self.index, "./models/index.ivf")
self.index = faiss.read_index("./models/index.ivf")
self.metadata = [{"fewshot_examaple": fewshot_examaple} for fewshot_examaple in self.few_shot_example_text]
def predict(self, prompt: str, is_multiple_choice: bool) -> str:
task_description = "Given a online shopping user query, retrieve relevant Question-Answer that similar to the query."
query_text = ' ' + prompt
query_embed = self.embed_model.encode([self.get_detailed_instruct(task_description, query_text)])[0]
topk = 3
scores, indices = self.index.search(np.array([query_embed]).astype(np.float32), topk)
# Retrieve and process results
exmaple_prompt = []
for score, idx in zip(scores[0], indices[0]):
print(f'score:{score} meta data:{self.metadata[idx]["fewshot_examaple"]}')
fewshot_examaple = self.metadata[idx]["fewshot_examaple"]
exmaple_prompt.append(fewshot_examaple)
if len(exmaple_prompt) > 0:
prompt_example = self.system_prompt + 'Here are some similar questions and answers you can refer to:\n'
for i in exmaple_prompt:
prompt_example += i+'\n'
prompt_example += 'Now answer the Question:' + prompt
else:
prompt_example = self.system_prompt + '\nNow answer the Question:' + prompt
print(prompt_example)
if is_multiple_choice:
# todo add retrive few shot example
inputs = self.tokenizer.encode(prompt_example, add_special_tokens=False, return_tensors="pt")
inputs = inputs.cuda()
if is_multiple_choice:
generate_ids = self.model.generate(inputs, max_new_tokens=1, temperature=0.1, eos_token_id=self.terminators)
result = self.tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
generation = result[len(prompt_example):]
else:
messages = [
{"role": "system", "content": prompt_example[:len(self.system_prompt)]},
{"role": "user", "content": prompt_example[len(self.system_prompt):]},
]
input_ids = self.tokenizer.apply_chat_template(
messages,
add_generation_prompt=True,
return_tensors="pt"
).to(self.model.device)