Machine learning/Chatbot

[챗봇] faiss로 빠르게 유사도 검색하기(Similarity Search)

Acdong 2022. 7. 18. 16:29
728x90

Faiss 는 Facebook AI 에서 개발한 유사도 검색 모델이다.

밀집 벡터의 효율적인 유사성 검색 및 클러스터링을 위한 라이브러리입니다.

Faiss 는 numpy 나 torch 에서 제공해주는 cosine_similarity 보다 훨씬 빠릅니다.

 

빠른 이유는 벡터들 간의 연관성까지 포함하여 임베딩 정보를 가지고 있기 때문입니다.

즉,  벡터 길이(n)가 고정되어 있을 경우에는 빠른속도를 기대할 수 있지만

매번 다른 벡터들일 경우엔 매번 벡터간 연관성 계산 + 유사도 계산이 필요하기 때문에 기존 

numpy 함수를 사용하는 것이 더 빠릅니다.

 

즉 faiss 는 길이(n)를 제한하는 대신 미리 벡터끼리의 정보를 계산해두고 그것을 이용하여 빠르게 검색합니다.

( 틀리면 마구마구 지적 부탁드립니다. )

 

실습을 통해 알아보겠습니다.

 


Faiss 설치 방법

# CPU-only version
$ conda install -c pytorch faiss-cpu

# GPU(+CPU) version
$ conda install -c pytorch faiss-gpu

# or for a specific CUDA version
$ conda install -c pytorch faiss-gpu cudatoolkit=10.2 # for CUDA 10.2

 

데이터 셋 : https://github.com/songys/Chatbot_data

pairwise 모델 : https://huggingface.co/Huffon/sentence-klue-roberta-base 

 

준비단계

(1). 데이터셋에 질문(Q)를 pairwise 모델로 전부 임베딩

(2). 임베딩 벡터들을 저장 (.npy)

 

패키지 로드

import pandas as pd
import numpy as np
import faiss
from sentence_transformers import SentenceTransformer , util

데이터 로드

#데이터 불러오기
df = pd.read_csv("./ChatbotData.csv")

#임베딩 벡터 불러오기
embeddings = np.load("./embeddings.npy")

#변환기 불러오기
embedder = SentenceTransformer("Huffon/sentence-klue-roberta-base")

 

불러온 벡터의 차원이 맞는지 확인합니다.

# 벡터 차원 확인하기
embeddings.shape
(103675, 768)

 

Faiss 적용하기

# faiss 계산하기

index = faiss.IndexFlatL2(embeddings.shape[1]) # 초기화 : 벡터의 크기를 지정
index.add(embeddings) # 임베딩을 추가

여기서 IndexFlatL2 는 각 벡터의 유사성 또는 각 벡터의 근접성을 측정하는 데 사용하는 거리 메트릭입니다.

여기서 L2 는 유클리드 거리를 의미합니다.

index.is_trained # 추가가 되었는지 확인하기
index.ntotal # 임베딩 수 확인하기

 

유사도 검색

top_k = 100
query = "사랑했던 사람이 떠났어"
query_embedding = embedder.encode(query, normalize_embeddings=True ,convert_to_tensor=True)

distances, indices = index.search(np.expand_dims(query_embedding,axis=0),top_k)

유사도 검색은 쉽게 index.search 를 사용하면 할 수 있습니다.

결과는 튜플의 형태로 나오게 되는데 앞에(distances)는 각각의 벡터들의 거리가 저장되고, 

뒤에(indices)는 해당하는 인덱스를 반환됩니다.

top_k 는 몇개를 추출할 것인지에 대한 옵션이고 자동으로 거리가 가까운 순서로 정렬되어 반환됩니다.

# 결과 확인
temp = df.iloc[indices[0]]
#temp
temp['distances'] = distances[0]
temp[['user','system','distances']].head(10)

검색 결과

#index 저장하기
faiss.write_index(index,"sts.index")

#인덱스 불러오기
index = faiss.read_index("./sts.index")

한번 계산한 index 는 저장하여 다음번에 불러오기만 해서 사용할 수 있습니다.

 

속도 테스트 결과

 

총 10만개의 벡터를 전부 cosine_similarity를 했을 경우에는 10초 정도 결렸고

faiss 모델은 0.2~0.3초 소요되었다.

 

검색기반 챗봇은 검색 성능과 속도가 가장 중요한데 faiss 라이브러리를 사용하여 엄청난 성능향상을 기대할 수 있었습니다.

참고 : https://www.youtube.com/watch?v=sKyvsdEv6rk&t=22s 

  https://github.com/facebookresearch/faiss/wiki/Getting-started

  https://github.com/facebookresearch/faiss/blob/main/INSTALL.md

반응형