ensemble-triple-qa / test_ensemble.py
dbalasub's picture
Upload TestEnsembleQAPipeline
6eebaaf verified
from typing import List, Tuple
import numpy as np
import pandas as pd
from transformers import AutoModelForSeq2SeqLM, AutoTokenizer, RobertaForSequenceClassification, RobertaTokenizer, ElectraModel, ElectraForCausalLM, GPT2Tokenizer, GPT2Model, GPT2LMHeadModel
import torch
import os
import json
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import gzip
from transformers import Text2TextGenerationPipeline
class TestEnsembleQAPipeline(Text2TextGenerationPipeline):
def __init__(self, model=None, tokenizer=None, framework="pt", **kwargs):
super().__init__(model=model, tokenizer=tokenizer, framework=framework)
self.quiz_bowl_model = QuizBowlModel() # Initializes your QuizBowl model
def _forward(self, model_inputs, **generate_kwargs):
questions = [self.tokenizer.decode(ids, skip_special_tokens=True) for ids in model_inputs["input_ids"]]
results = self.quiz_bowl_model.guess_and_buzz(questions)
return results
def postprocess(self, model_outputs):
results = {}
for output in model_outputs:
guess_text = output[0]
confidence = output[1]
results = {'guess': guess_text, 'confidence': confidence}
return results
class QuizBowlModel:
def __init__(self):
model_configs = {
'flan-t5-large': {'model': 'google/flan-t5-large', 'tokenizer': 'google/flan-t5-large'},
'flan-t5-small': {'model': 'google/flan-t5-small', 'tokenizer': 'google/flan-t5-small'},
'flan-t5-base': {'model': 'google/flan-t5-base', 'tokenizer': 'google/flan-t5-base'}
}
self.models = {}
self.tokenizers = {}
self.load_models(model_configs)
def load_models(self, model_configs):
"""Load multiple models based on configuration."""
for model_name, config in model_configs.items():
tokenizer = AutoTokenizer.from_pretrained(config['tokenizer'])
model = AutoModelForSeq2SeqLM.from_pretrained(config['model'])
model.eval()
self.models[model_name] = model
self.tokenizers[model_name] = tokenizer
def guess_and_buzz(self, question_texts):
total_answers = [self.generate_answers(question) for question in question_texts]
# for question, model_answers in zip(question_texts, total_answers):
# print(f"{question}\nModel Guesses: {model_answers}\n")
return [self.ensemble_tfidf_voting(answers) for answers in total_answers]
def generate_answers(self, question):
raw_answers = []
for model_name, model in self.models.items():
tokenizer = self.tokenizers[model_name]
input_ids = tokenizer(question, return_tensors="pt", padding=True, truncation=True).input_ids
with torch.no_grad():
outputs = model.generate(input_ids, max_new_tokens=5, output_scores=True, return_dict_in_generate=True)
decoded_text = tokenizer.decode(outputs.sequences[0], skip_special_tokens=True)
confidence_score = self.calculate_confidence(outputs.scores)
raw_answers.append((decoded_text, confidence_score))
total_scores = sum([score for _, score in raw_answers])
answers = [(text, score / total_scores if total_scores > 0 else 0) for text, score in raw_answers]
return answers
def calculate_confidence(self, scores):
if scores:
log_probs = [torch.nn.functional.log_softmax(score, dim=-1) for score in scores]
selected_log_probs = [log_probs[i][0, scores[i].argmax()].item() for i in range(len(log_probs))]
confidence_score = np.exp(np.mean(selected_log_probs))
else:
confidence_score = None
return confidence_score
def ensemble_tfidf_voting(self, answers):
return max(answers, key=lambda x: x[1]) if answers else (None, 0)
if __name__ == "__main__":
# Initialize the QuizBowlModel
model = QuizBowlModel()
hardcoded_questions = ["Who wrote 'Pride and Prejudice'?", "What is the capital of France?"]
# Load questions from a compressed JSON file
file_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'data', 'qanta.guessdev.json.gz')
with gzip.open(file_path, 'rt', encoding='utf-8') as file:
data = json.load(file)
true_answers = ["Jane Austen", "Paris"]
loaded_questions = [item['text'] for item in data]
true_answers += [item['answer'] for item in data]
questions = hardcoded_questions + loaded_questions[:8] # Increase if needed
total_answers = model.guess_and_buzz(questions)
print("Final Answers with Voting Mechanism:")
# Display the model's after entire ensemble approach
for question, model_answers, true_answer in zip(questions, total_answers, true_answers):
print(f"{question}\nModel Guesses: {model_answers}\nCorrect Answer: {true_answer}\n\n")