الإجابة عن الأسئلة باستخدام ميلفوس وكوهير
توضّح هذه الصفحة كيفية إنشاء نظام للإجابة على الأسئلة استنادًا إلى مجموعة بيانات SQuAD باستخدام ميلفوس كقاعدة بيانات المتجهات و Cohere كنظام تضمين.
قبل أن تبدأ
تتطلب مقتطفات التعليمات البرمجية في هذه الصفحة تثبيت حزم pymilvus و cohere و pandas و numpy و tqdm. من بين هذه الحزم، pymilvus هو عميل لـ Milvus. إذا لم تكن موجودة على نظامك، قم بتشغيل الأوامر التالية لتثبيتها:
pip install pymilvus cohere pandas numpy tqdm
ثم تحتاج إلى تحميل الوحدات النمطية المراد استخدامها في هذا الدليل.
import cohere
import pandas
import numpy as np
from tqdm import tqdm
from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection, utility
المعلمات
هنا يمكننا العثور على المعلمات المستخدمة في المقتطفات التالية. يجب تغيير بعضها لتناسب بيئتك. بجانب كل منها وصف لماهيته.
FILE = 'https://rajpurkar.github.io/SQuAD-explorer/dataset/train-v2.0.json' # The SQuAD dataset url
COLLECTION_NAME = 'question_answering_db' # Collection name
DIMENSION = 1024 # Embeddings size, cohere embeddings default to 4096 with the large model
COUNT = 5000 # How many questions to embed and insert into Milvus
BATCH_SIZE = 96 # How large of batches to use for embedding and insertion
MILVUS_HOST = 'localhost' # Milvus server URI
MILVUS_PORT = '19530'
COHERE_API_KEY = 'replace-this-with-the-cohere-api-key' # API key obtained from Cohere
لمعرفة المزيد عن النموذج ومجموعة البيانات المستخدمة في هذه الصفحة، راجع co:here و SQuAD.
إعداد مجموعة البيانات
في هذا المثال، سنستخدم في هذا المثال مجموعة بيانات ستانفورد للإجابة على الأسئلة (SQuAD) كمصدر الحقيقة للإجابة على الأسئلة. تأتي مجموعة البيانات هذه على شكل ملف JSON وسنستخدم بانداس لتحميلها.
# Download the dataset
dataset = pandas.read_json(FILE)
# Clean up the dataset by grabbing all the question answer pairs
simplified_records = []
for x in dataset['data']:
for y in x['paragraphs']:
for z in y['qas']:
if len(z['answers']) != 0:
simplified_records.append({'question': z['question'], 'answer': z['answers'][0]['text']})
# Grab the amount of records based on COUNT
simplified_records = pandas.DataFrame.from_records(simplified_records)
simplified_records = simplified_records.sample(n=min(COUNT, len(simplified_records)), random_state = 42)
# Check the length of the cleaned dataset matches count
print(len(simplified_records))
يجب أن يكون الناتج هو عدد السجلات في مجموعة البيانات
5000
إنشاء مجموعة
يتعامل هذا القسم مع ميلفوس وإعداد قاعدة البيانات لحالة الاستخدام هذه. داخل ميلفوس، نحتاج إلى إعداد مجموعة وفهرستها.
# Connect to Milvus Database
connections.connect(host=MILVUS_HOST, port=MILVUS_PORT)
# Remove collection if it already exists
if utility.has_collection(COLLECTION_NAME):
utility.drop_collection(COLLECTION_NAME)
# Create collection which includes the id, title, and embedding.
fields = [
FieldSchema(name='id', dtype=DataType.INT64, is_primary=True, auto_id=True),
FieldSchema(name='original_question', dtype=DataType.VARCHAR, max_length=1000),
FieldSchema(name='answer', dtype=DataType.VARCHAR, max_length=1000),
FieldSchema(name='original_question_embedding', dtype=DataType.FLOAT_VECTOR, dim=DIMENSION)
]
schema = CollectionSchema(fields=fields)
collection = Collection(name=COLLECTION_NAME, schema=schema)
# Create an IVF_FLAT index for collection.
index_params = {
'metric_type':'IP',
'index_type':"IVF_FLAT",
'params':{"nlist": 1024}
}
collection.create_index(field_name="original_question_embedding", index_params=index_params)
collection.load()
إدراج البيانات
بمجرد إعداد المجموعة نحتاج إلى البدء في إدراج بياناتنا. يتم ذلك في ثلاث خطوات
- قراءة البيانات
- تضمين الأسئلة الأصلية، و
- وإدراج البيانات في المجموعة التي أنشأناها للتو على ميلفوس.
في هذا المثال، تتضمن البيانات في هذا المثال السؤال الأصلي، وتضمين السؤال الأصلي، وإجابة السؤال الأصلي.
# Set up a co:here client.
cohere_client = cohere.Client(COHERE_API_KEY)
# Extract embeddings from questions using Cohere
def embed(texts, input_type):
res = cohere_client.embed(texts, model='embed-multilingual-v3.0', input_type=input_type)
return res.embeddings
# Insert each question, answer, and qustion embedding
total = pandas.DataFrame()
for batch in tqdm(np.array_split(simplified_records, (COUNT/BATCH_SIZE) + 1)):
questions = batch['question'].tolist()
embeddings = embed(questions, "search_document")
data = [
{
'original_question': x,
'answer': batch['answer'].tolist()[i],
'original_question_embedding': embeddings[i]
} for i, x in enumerate(questions)
]
collection.insert(data=data)
time.sleep(10)
طرح الأسئلة
بمجرد إدراج جميع البيانات في مجموعة ميلفوس، يمكننا طرح أسئلة على النظام من خلال أخذ عبارة السؤال وتضمينها مع كوهير والبحث باستخدام المجموعة.
قد تكون عمليات البحث التي يتم إجراؤها على البيانات بعد الإدراج مباشرةً أبطأ قليلاً لأن البحث في البيانات غير المفهرسة يتم بطريقة القوة الغاشمة. بمجرد فهرسة البيانات الجديدة تلقائيًا، ستزداد سرعة عمليات البحث.
# Search the cluster for an answer to a question text
def search(text, top_k = 5):
# AUTOINDEX does not require any search params
search_params = {}
results = collection.search(
data = embed([text], "search_query"), # Embeded the question
anns_field='original_question_embedding',
param=search_params,
limit = top_k, # Limit to top_k results per search
output_fields=['original_question', 'answer'] # Include the original question and answer in the result
)
distances = results[0].distances
entities = [ x.entity.to_dict()['entity'] for x in results[0] ]
ret = [ {
"answer": x[1]["answer"],
"distance": x[0],
"original_question": x[1]['original_question']
} for x in zip(distances, entities)]
return ret
# Ask these questions
search_questions = ['What kills bacteria?', 'What\'s the biggest dog?']
# Print out the results in order of [answer, similarity score, original question]
ret = [ { "question": x, "candidates": search(x) } for x in search_questions ]
يجب أن تكون المخرجات مشابهة لما يلي:
# Output
#
# [
# {
# "question": "What kills bacteria?",
# "candidates": [
# {
# "answer": "farming",
# "distance": 0.6261022090911865,
# "original_question": "What makes bacteria resistant to antibiotic treatment?"
# },
# {
# "answer": "Phage therapy",
# "distance": 0.6093736886978149,
# "original_question": "What has been talked about to treat resistant bacteria?"
# },
# {
# "answer": "oral contraceptives",
# "distance": 0.5902313590049744,
# "original_question": "In therapy, what does the antibacterial interact with?"
# },
# {
# "answer": "slowing down the multiplication of bacteria or killing the bacteria",
# "distance": 0.5874154567718506,
# "original_question": "How do antibiotics work?"
# },
# {
# "answer": "in intensive farming to promote animal growth",
# "distance": 0.5667208433151245,
# "original_question": "Besides in treating human disease where else are antibiotics used?"
# }
# ]
# },
# {
# "question": "What's the biggest dog?",
# "candidates": [
# {
# "answer": "English Mastiff",
# "distance": 0.7875324487686157,
# "original_question": "What breed was the largest dog known to have lived?"
# },
# {
# "answer": "forest elephants",
# "distance": 0.5886962413787842,
# "original_question": "What large animals reside in the national park?"
# },
# {
# "answer": "Rico",
# "distance": 0.5634892582893372,
# "original_question": "What is the name of the dog that could ID over 200 things?"
# },
# {
# "answer": "Iditarod Trail Sled Dog Race",
# "distance": 0.546872615814209,
# "original_question": "Which dog-sled race in Alaska is the most famous?"
# },
# {
# "answer": "part of the family",
# "distance": 0.5387814044952393,
# "original_question": "Most people today describe their dogs as what?"
# }
# ]
# }
# ]