Milvus와 Cohere를 사용한 질문 답변하기
이 페이지에서는 Milvus를 벡터 데이터베이스로, Cohere를 임베딩 시스템으로 사용하여 SQuAD 데이터셋에 기반한 질문 답변 시스템을 만드는 방법을 설명합니다.
시작하기 전에
이 페이지의 코드 스니펫을 사용하려면 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
컬렉션 만들기
이 섹션에서는 Milvus와 이 사용 사례를 위한 데이터베이스 설정에 대해 다룹니다. Milvus 내에서 컬렉션을 설정하고 색인을 생성해야 합니다.
# 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()
데이터 삽입
컬렉션을 설정했으면 데이터 삽입을 시작해야 합니다. 이 작업은 다음 세 단계로 이루어집니다.
- 데이터 읽기
- 원래 질문 삽입하기
- Milvus에서 방금 만든 컬렉션에 데이터를 삽입합니다.
이 예제에서는 데이터에 원본 질문, 원본 질문의 임베딩, 원본 질문에 대한 답변이 포함됩니다.
# 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)
질문하기
모든 데이터가 Milvus 컬렉션에 삽입되면, 질문 문구를 가져와서 Cohere로 임베딩하고 컬렉션으로 검색하여 시스템에 질문할 수 있습니다.
삽입 직후 데이터에 대한 검색은 색인되지 않은 데이터를 무차별 대입 방식으로 검색하기 때문에 속도가 약간 느릴 수 있습니다. 새 데이터가 자동으로 색인되면 검색 속도가 빨라집니다.
# 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?"
# }
# ]
# }
# ]