ManualRAG / rag_core.py
bash98's picture
Update rag_core.py
a43117e verified
Raw History Blame Contribute Delete
2.89 kB
"""Manual retrieval-augmented generation for a document Q&A lesson.
Both the embedding model and the generation model run on CPU. The generation
model is loaded only when a user asks for an actual generated answer.
"""
import numpy as np
import torch
from datasets import load_dataset
from sentence_transformers import SentenceTransformer
from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
EMBEDDING_MODEL = "sentence-transformers/all-MiniLM-L6-v2"
GENERATION_MODEL = "google/flan-t5-small"
MIN_SCORE = 0.30 # Teaching heuristic, NOT calibrated confidence.
NO_ANSWER = "I cannot answer this from the supplied passages."
DATASET_ID = "rajpurkar/squad"
DATASET_REVISION = "7b6d24c440a36b6815f21b70d25016731768db1f"
corpus = []
source_questions = []
embedder = None
passage_embeddings = None
tokenizer = None
generator = None
def load_passage_sample(embedding_tokenizer):
"""Stream a reproducible sample of 30 distinct SQuAD contexts."""
rows = load_dataset(
DATASET_ID,
split="train",
revision=DATASET_REVISION,
streaming=True,
)
passages, questions = [], []
seen_contexts = set()
title_counts = {}
for row in rows.take(6000):
title = row["title"].replace("_", " ")
context = row["context"].strip()
if (
context in seen_contexts
or title_counts.get(title, 0) >= 3
or len(title) > 35
or title == "Genocide"
):
continue
token_count = len(
embedding_tokenizer(
title + ". " + context,
truncation=False,
verbose=False,
)["input_ids"]
)
if token_count > 200:
continue
passage_id = f"P{len(passages) + 1:02d}"
passages.append(
{
"id": passage_id,
"title": title,
"text": context,
"source": "SQuAD train / Wikipedia: " + title,
"squad_id": row["id"],
}
)
questions.append(
{
"query": row["question"],
"expected_ids": [passage_id],
"squad_id": row["id"],
"answer_spans": row["answers"]["text"],
}
)
seen_contexts.add(context)
title_counts[title] = title_counts.get(title, 0) + 1
if len(passages) == 30:
break
if len(passages) != 30:
raise RuntimeError(
"The Hub sample did not produce 30 passages. "
"Check dataset access and the specified revision."
)
return passages, questions
def make_evaluation_cases(questions):
"""Create answerable and unanswerable evaluation examples."""
if len(questions) != 30:
raise ValueError("Load the Hub sample before creating evaluation cases.")