الإجابة عن الأسئلة باستخدام ميلفوس ومعانقة الوجه
يعمل نظام الإجابة عن الأسئلة المستند إلى البحث الدلالي من خلال إيجاد السؤال الأكثر تشابهًا من مجموعة بيانات لأزواج الأسئلة والأجوبة لسؤال استعلام معين. وبمجرد تحديد السؤال الأكثر تشابهًا، يتم اعتبار الإجابة المقابلة من مجموعة البيانات كإجابة للاستعلام. يعتمد هذا النهج على مقاييس التشابه الدلالي لتحديد التشابه بين الأسئلة واسترجاع الإجابات ذات الصلة.
يوضح هذا البرنامج التعليمي كيفية إنشاء نظام للإجابة على الأسئلة باستخدام Hugging Face كمحمّل بيانات ومولد تضمين لمعالجة البيانات وMilvus كقاعدة بيانات متجهة للبحث الدلالي.
قبل أن تبدأ
تحتاج إلى التأكد من تثبيت جميع التبعيات المطلوبة:
pymilvus
: حزمة بايثون تعمل مع خدمة قاعدة بيانات المتجهات التي تعمل بواسطة ميلفوس أو زيليز كلاود.datasets
transformers
: حزم عناق الوجه تدير البيانات وتستخدم النماذج.torch
: مكتبة قوية توفر حساب الموتر الفعال وأدوات التعلم العميق.
$ pip install --upgrade pymilvus transformers datasets torch
إذا كنت تستخدم Google Colab، لتمكين التبعيات المثبتة للتو، قد تحتاج إلى إعادة تشغيل وقت التشغيل. (انقر على قائمة "وقت التشغيل" في أعلى الشاشة، واختر "إعادة تشغيل الجلسة" من القائمة المنسدلة).
إعداد البيانات
في هذا القسم، سنقوم بتحميل أمثلة على أزواج الأسئلة والأجوبة من مجموعات بيانات عناق الوجه. كعرض توضيحي، نأخذ بيانات جزئية فقط من تقسيم التحقق من صحة SQuAD.
from datasets import load_dataset
DATASET = "squad" # Name of dataset from HuggingFace Datasets
INSERT_RATIO = 0.001 # Ratio of example dataset to be inserted
data = load_dataset(DATASET, split="validation")
# Generates a fixed subset. To generate a random subset, remove the seed.
data = data.train_test_split(test_size=INSERT_RATIO, seed=42)["test"]
# Clean up the data structure in the dataset.
data = data.map(
lambda val: {"answer": val["answers"]["text"][0]},
remove_columns=["id", "answers", "context"],
)
# View summary of example data
print(data)
Dataset({
features: ['title', 'question', 'answer'],
num_rows: 11
})
لتوليد تضمينات للأسئلة، يمكنك تحديد نموذج تضمين نصي من نماذج تعانق الوجوه. في هذا البرنامج التعليمي، سوف نستخدم نموذج تضمين جمل صغير كل -MiniLM-L6-v2 كمثال.
from transformers import AutoTokenizer, AutoModel
import torch
MODEL = (
"sentence-transformers/all-MiniLM-L6-v2" # Name of model from HuggingFace Models
)
INFERENCE_BATCH_SIZE = 64 # Batch size of model inference
# Load tokenizer & model from HuggingFace Hub
tokenizer = AutoTokenizer.from_pretrained(MODEL)
model = AutoModel.from_pretrained(MODEL)
def encode_text(batch):
# Tokenize sentences
encoded_input = tokenizer(
batch["question"], padding=True, truncation=True, return_tensors="pt"
)
# Compute token embeddings
with torch.no_grad():
model_output = model(**encoded_input)
# Perform pooling
token_embeddings = model_output[0]
attention_mask = encoded_input["attention_mask"]
input_mask_expanded = (
attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
)
sentence_embeddings = torch.sum(
token_embeddings * input_mask_expanded, 1
) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)
# Normalize embeddings
batch["question_embedding"] = torch.nn.functional.normalize(
sentence_embeddings, p=2, dim=1
)
return batch
data = data.map(encode_text, batched=True, batch_size=INFERENCE_BATCH_SIZE)
data_list = data.to_list()
إدراج البيانات
الآن لدينا أزواج الأسئلة والأجوبة جاهزة مع تضمينات الأسئلة. الخطوة التالية هي إدراجها في قاعدة بيانات المتجهات.
سنحتاج أولاً إلى الاتصال بخدمة ميلفوس وإنشاء مجموعة ميلفوس.
from pymilvus import MilvusClient
MILVUS_URI = "./huggingface_milvus_test.db" # Connection URI
COLLECTION_NAME = "huggingface_test" # Collection name
DIMENSION = 384 # Embedding dimension depending on model
milvus_client = MilvusClient(MILVUS_URI)
if milvus_client.has_collection(collection_name=COLLECTION_NAME):
milvus_client.drop_collection(collection_name=COLLECTION_NAME)
milvus_client.create_collection(
collection_name=COLLECTION_NAME,
dimension=DIMENSION,
auto_id=True, # Enable auto id
enable_dynamic_field=True, # Enable dynamic fields
vector_field_name="question_embedding", # Map vector field name and embedding column in dataset
consistency_level="Strong", # To enable search with latest data
)
أما بالنسبة لحجة MilvusClient
:
- يعد تعيين
uri
كملف محلي، على سبيل المثال./milvus.db
، هو الطريقة الأكثر ملاءمة، حيث أنه يستخدم تلقائيًا Milvus Lite لتخزين جميع البيانات في هذا الملف. - إذا كان لديك حجم كبير من البيانات، يمكنك إعداد خادم Milvus أكثر أداءً على docker أو kubernetes. في هذا الإعداد، يُرجى استخدام الخادم uri، على سبيل المثال
http://localhost:19530
، كـuri
. - إذا كنت ترغب في استخدام Zilliz Cloud، الخدمة السحابية المدارة بالكامل لـ Milvus، اضبط
uri
وtoken
، والتي تتوافق مع نقطة النهاية العامة ومفتاح Api في Zilliz Cloud.
أدخل جميع البيانات في المجموعة:
milvus_client.insert(collection_name=COLLECTION_NAME, data=data_list)
{'insert_count': 11,
'ids': [450072488481390592, 450072488481390593, 450072488481390594, 450072488481390595, 450072488481390596, 450072488481390597, 450072488481390598, 450072488481390599, 450072488481390600, 450072488481390601, 450072488481390602],
'cost': 0}
طرح الأسئلة
بمجرد إدراج جميع البيانات في ميلفوس، يمكننا طرح الأسئلة ومعرفة أقرب الإجابات.
questions = {
"question": [
"What is LGM?",
"When did Massachusetts first mandate that children be educated in schools?",
]
}
# Generate question embeddings
question_embeddings = [v.tolist() for v in encode_text(questions)["question_embedding"]]
# Search across Milvus
search_results = milvus_client.search(
collection_name=COLLECTION_NAME,
data=question_embeddings,
limit=3, # How many search results to output
output_fields=["answer", "question"], # Include these fields in search results
)
# Print out results
for q, res in zip(questions["question"], search_results):
print("Question:", q)
for r in res:
print(
{
"answer": r["entity"]["answer"],
"score": r["distance"],
"original question": r["entity"]["question"],
}
)
print("\n")
Question: What is LGM?
{'answer': 'Last Glacial Maximum', 'score': 0.956273078918457, 'original question': 'What does LGM stands for?'}
{'answer': 'coordinate the response to the embargo', 'score': 0.2120140939950943, 'original question': 'Why was this short termed organization created?'}
{'answer': '"Reducibility Among Combinatorial Problems"', 'score': 0.1945795714855194, 'original question': 'What is the paper written by Richard Karp in 1972 that ushered in a new era of understanding between intractability and NP-complete problems?'}
Question: When did Massachusetts first mandate that children be educated in schools?
{'answer': '1852', 'score': 0.9709997177124023, 'original question': 'In what year did Massachusetts first require children to be educated in schools?'}
{'answer': 'several regional colleges and universities', 'score': 0.34164726734161377, 'original question': 'In 1890, who did the university decide to team up with?'}
{'answer': '1962', 'score': 0.1931006908416748, 'original question': 'When were stromules discovered?'}