faiss
이전의 embedding 게시물과 이어지는 내용
이번에는 faiss를 가져와서 문장을 입력하면 유사한 문장을 찾고 유사도 점수를 보여주게 해보자.
전체 코드
import faiss
# 문장 임베딩을 사용해 인덱스 생성
dimension = sentence_embeddings.shape[1]
index = faiss.IndexFlatL2(dimension) # L2 거리 기반 인덱스
# 인덱스에 벡터 추가
index.add(np.array(sentence_embeddings))
query = "문장을 입력하세요"
query_vec = model.encode(query)
# 유사한 문장 3개 찾기
D, I = index.search(np.array([query_vec]), k=3)
# 결과 출력
for idx, score in zip(I[0], D[0]):
print(f"유사 문장: {sentences[idx]}, 유사도 점수: {score}")
dimension = sentence_embeddings.shape[1]
임베딩한 문장에 .shpae를 하면 (행,렬) 형태의 튜플이 된다.
만약 10개의 문장이고 200차원의 임베딩 벡터라면 (10,200) 형태이다. 이 때
.shape[0] =10 ->문장의 개수
.shape[1]=200 ->임베딩 벡터의 차원
index = faiss.IndexFlatL2(dimension)
faiss.IndexFlatL2 는 벡터 데이터를 인덱스에 저장하여 유클리드 거리 기반으로 검색할 수 있게 하는 기본 인덱스를 설정하는 부분이다. 인덱스가 있어야 나중에 유사도를 검색할 때 빠르게 찾을 수 있다.
faiss.IndexFlatL2(dimension)는 차원이 dimension인 벡터를 저장하고 인덱스를 설정한다.
index.add(np.array(sentence_embeddings))
위에서 설정한 인덱스를 벡터 데이터에 추가해준다.
이 코드가 없으면 단순히 인덱스가 어떻다고 정해지기만 했을 뿐 사용할수는 없다.
np.array는 넘파이 형태 배열로 반환해주는 함수
D, I = index.search(np.array([query_vec]), k=3)
index.search는 유사도(D)와 인덱스(I)를 반환한다.
이 코드는 query_vec과 가장 유사한 3개의 벡터를 찾는 코드이다.
예를 들어
D=[[0.5, 0.7, 0.8]]
I=[[0,3,2]]
이렇게 반환되었다면, 0번인덱스 문장의 유사도는 0.5, 3번 인덱스 문장의 유사도는 0.7, 2번인덱스 문장의 유사도는 0.8이다.
for idx, score in zip(I[0], D[0]):
print(f"유사 문장: {sentences[idx]}, 유사도 점수: {score}")
zip은 리스트를 병렬형태 튜플로 묶어주는 함수
그러니까 위의 예시에서 zip을 쓰면
(index, score) = (0, 0.5), (3, 0.7), (2, 0.8) 이렇게 된다.
이걸로 유사한 문장과 유사도 점수를 보여줄 수 있다.
결과
1.

참고로, 이전 cosine similarity를 이용했던 결과와 비교해보면 faiss가 더 우수함을 알 수 있다.

2.

비교 (cosine_similarity)

이렇게 잘 안나오는 이유는 아마 텍스트 전처리가 안되었기 때문이 아닐까? 불용어라든지 어간추출이라든지
3.


결과는 비슷하지만 점 하나 차이로 유사도 점수가 크게 달라진 것을 볼 수 있다. 이런 문장부호도 텍스트 전처리로 잘 처리해주면 더 좋겠다.
what's next
모듈화된 텍스트 전처리 함수 + sentence transformer보다 더 좋은 모델로 다시 해보기
or
object detection model
사담
명량 한산 노량 다 봤는데 나는 한산이 제일 재밌었다.
이순신 장군은 무관이기는 하지만 선비의 면모도 있을것이라 생각했는데 내 머릿속에 있던 이미지와 딱 맞는 배우의 연기여서 그랬던 것 같다.
