본문 바로가기
Deep Learning

[Langchain] FAISS에서 cosine similarity 사용하기

by Yonghip 2024. 11. 25.

기존에 구현했던 RAG 성능을 개선하는 PoC 느낌의 업무를 받아서 처음부터 db나 chunker를 새로 모색하기보다는 기존에 사용한 라이브러리를 그대로 사용했다.

 

chunk, retrieval 쪽은 대게 langchain+FAISS로 구현되어 있었는데 retrieval 성능이 어떻게 해도 좋아지지 않아서 이것저것 찾아봤는데 점수 쪽에서 뭔가 이상하다고 느꼈다.

FAISS로 vector DB를 만들 때 보통 vectorDB.from_documents( )를 사용했는데 이를 이용한 similarity_search는 L2 거리 기반임을 알 수 있었다. vector 거리 비교에 cosine similarity를 사용하지 않아 성능이 낮은 것이라 판단했다.

그렇다고 다른 라이브러리나 벡터 db를 쓰기에는 관련 지식이 전무해 최대한 기존 langchain+FAISS 조합을 유지하고 싶어 일단은 그냥 눈 감고 사용했다.

 

퇴근하고 너무 열받아 조금 검색하니 바로 해답이(거기다 한국어로 친철하게)나와서 공유해보려 한다.

FAISS.from_documets( )에서 distance_metric 지정하기

db = FAISS.from_documents(doc_texts, embedding=embeddings, distance_strategy = DistanceStrategy.MAX_INNER_PRODUCT)

위의 코드를 사용하면 cosine similarity를 사용해 index를 생성할 수 있다.

이를 사용하지 않았을 때와 사용했을 때 retrieval 결과가 다른 걸 알 수 있다. 이 예제는 Dacon의 예시 데이터라 semantic search를 하기에는 적합하지 않아 검증 코드를 덧붙이겠다.

 

def l2_distance(vec1, vec2):
    return np.sqrt(np.sum((vec1 - vec2) ** 2))

def cosine_similarity(vec1, vec2):
    return np.dot(vec1, vec2) / (norm(vec1) * norm(vec2))
    
print(doc_texts[-1].page_content)
###'The mitochondria are known as the powerhouse of the cell, providing energy for cellular activities.'

db = FAISS.from_documents(doc_texts, embedding=embeddings, distance_strategy = DistanceStrategy.MAX_INNER_PRODUCT, normalize_L2 = True)
db.similarity_search_with_score_by_vector(embeddings.embed_query("The mitochondria"), k=1)

###[(Document(metadata={'source': 'Biology Notes'}, page_content='The mitochondria are known as the powerhouse of the cell, providing energy for cellular activities.'),
  0.72040486)]
  
print(cosine_similarity(embeddings.embed_query(doc_texts[-1].page_content), embeddings.embed_query("The mitochondria")))
###0.7204048870290206

넘파이로 구현한 코사인 거리와 값이 동일한 걸 알 수 있다. 한 가지 주의점으로는 index 생성 시 "normalize_L2 = True" 인자를 설정하지 않으면 같은 거리가 재현되지 않는다. " normalize_L2 = False"(default)를 사용하면 코사인 유사도의 분모로 나눠주는 연산을 수행하지 않기 때문이다.

 

한 마디로 normalize해도 scailing으로 인한 값의 차가 존재하지만 retrieval 결과는 동일하다.

 

참고: https://wikidocs.net/231593

'Deep Learning' 카테고리의 다른 글

[Pytorch] ImageFolder label기준으로 split하기  (0) 2023.04.10
[Pytorch]Datasets and dataloaders  (0) 2023.03.23
[Pytorch]Autograd  (0) 2023.03.19
[Pytorch]Pytorch Basic  (0) 2023.03.19