RAG

RAG 벡터 검색 [7]

HeyTeddy 2024. 9. 2. 02:41
반응형
 

벡터 검색(Vector Search) 개요

벡터 검색은 데이터 간의 유사성을 기반으로 원하는 정보를 찾는 데 중요한 역할을 하는 기술로, 최근 자연어 처리(NLP), 컴퓨터 비전, 추천 시스템 등 다양한 분야에서 활용되고 있습니다. 이 글에서는 벡터 검색의 기본 개념인 유사도 검색과 MMR 알고리즘에 대해 설명하고, FAISS를 활용한 인덱스 생성 과정, 다양한 인덱스 유형의 성능 비교, 그리고 검색 결과의 Ranking이 필요한 이유와 해결 방법을 다루겠습니다.


유사도 검색(Similarity Search)

1. 유사도 검색 정의

유사도 검색(Similarity Search)은 주어진 쿼리와 데이터베이스 내의 데이터 간의 유사도를 측정하여 가장 유사한 결과를 반환하는 검색 방식입니다. 텍스트, 이미지, 오디오 등 다양한 데이터를 고차원 벡터로 변환한 후, 이 벡터들 사이의 거리를 계산하여 유사성을 평가합니다. 키워드 매칭에 의존하는 전통적인 검색 방식과 달리, 유사도 검색은 의미적으로 유사한 결과를 찾아내는 데 매우 유용합니다.

2. 유사도 검색 예시

  • 텍스트 유사도 검색: "Apple is a tech company"라는 문장을 입력하면, 데이터베이스에서 "Apple Inc. is a leading technology company."와 같은 의미적으로 유사한 문장을 찾아 반환합니다.
  • 이미지 유사도 검색: 특정 이미지를 입력하면, 데이터베이스에서 시각적으로 유사한 이미지를 찾아 반환합니다.
import faiss
import numpy as np

# 데이터베이스 내의 벡터(예: 문서 임베딩 벡터)
data_vectors = np.random.random((1000, 128)).astype('float32')

# 검색할 쿼리 벡터
query_vector = np.random.random((1, 128)).astype('float32')

# FAISS 인덱스 생성 및 데이터베이스 벡터 추가
index = faiss.IndexFlatL2(128)  # L2 거리 사용
index.add(data_vectors)

# 쿼리 벡터와 가장 유사한 벡터 찾기
k = 5  # 상위 5개의 유사한 결과를 찾음
distances, indices = index.search(query_vector, k)

# 결과 출력
print(f"Top {k} similar vectors' indices: {indices}")
print(f"Distances: {distances}")

MMR(Maximal Marginal Relevance)

1. MMR 정의

MMR(Maximal Marginal Relevance)은 검색 결과의 다양성을 보장하기 위해 사용되는 알고리즘입니다. 단순히 유사도가 높은 결과만을 반환하는 것이 아니라, 이미 선택된 결과와의 중복성을 최소화하면서 유사한 결과를 선택하는 방법입니다. 이를 통해 사용자는 보다 다양한 정보를 얻을 수 있습니다.

2. MMR의 사용성

MMR은 검색 결과가 너무 유사한 경우(예: 중복된 문서나 이미지)를 방지하여 검색 결과의 다양성을 높이는 데 유용합니다. 특히, 뉴스 기사나 추천 시스템에서 다양한 시각을 제공하는 데 효과적입니다.

3. MMR 프로세스

MMR의 기본 프로세스는 다음과 같습니다:

  1. 초기 검색 결과 중 가장 유사한 문서를 선택합니다.
  2. 이후 검색 결과에서, 이전에 선택된 결과와의 유사도를 고려하여 중복성을 최소화하면서 유사도가 높은 문서를 순차적으로 선택합니다.
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

def mmr(doc_embeddings, query_embedding, selected_embeddings, lambda_param=0.5):
    """
    MMR 알고리즘을 적용하여 다음으로 선택할 문서를 결정
    
    Parameters:
    - doc_embeddings: 전체 문서들의 임베딩 벡터 리스트
    - query_embedding: 쿼리 임베딩 벡터
    - selected_embeddings: 이미 선택된 문서들의 임베딩 벡터 리스트
    - lambda_param: 유사도와 다양성 간의 균형을 조절하는 파라미터
    
    Returns:
    - 다음으로 선택할 문서의 인덱스
    """
    sim_to_query = cosine_similarity(doc_embeddings, query_embedding.reshape(1, -1))
    sim_to_selected = cosine_similarity(doc_embeddings, selected_embeddings)
    max_sim_to_selected = np.max(sim_to_selected, axis=1)
    
    mmr_scores = lambda_param * sim_to_query - (1 - lambda_param) * max_sim_to_selected.reshape(-1, 1)
    
    return np.argmax(mmr_scores)

# 예시 데이터
doc_vectors = np.random.random((10, 128))
query_vec = np.random.random((128,))
selected_vecs = doc_vectors[:2]

next_doc_index = mmr(doc_vectors, query_vec, selected_vecs)
print(f"Next document to select: {next_doc_index}")

 


인덱스 생성 과정(FAISS 기준)

FAISS는 대규모 벡터 검색을 위한 효율적인 인덱스를 생성할 수 있는 다양한 방법을 제공합니다. 인덱스를 생성하는 과정에서 선택할 수 있는 다양한 옵션이 있으며, 각각의 방식은 검색 속도와 정확도에 영향을 미칩니다.

1. FAISS 인덱스 생성 과정

FAISS에서 벡터 데이터베이스 인덱스를 생성하는 과정은 다음과 같습니다:

  1. 벡터 데이터 준비: 검색할 대상이 되는 벡터들을 준비합니다.
  2. 인덱스 선택: 검색 목적에 맞는 FAISS 인덱스 유형을 선택합니다. 이는 검색 속도와 정확도에 직접적인 영향을 미칩니다.
  3. 인덱스 생성: 선택한 인덱스를 생성하고, 벡터 데이터를 추가합니다.
  4. 쿼리 수행: 생성된 인덱스를 사용해 쿼리 벡터와 유사한 벡터들을 검색합니다.

2. 인덱스 생성 원리 (IVF)

FAISS에서 많이 사용되는 인덱스 중 하나는 **IVF(Indexed Vectors and Feature Quantization)**입니다. IVF는 대규모 벡터 데이터베이스에서 검색 속도를 높이기 위해 벡터들을 여러 개의 클러스터로 나눈 후, 각 클러스터에 대한 인덱스를 생성합니다. 쿼리가 주어지면, 해당 쿼리와 가장 유사한 클러스터를 찾고, 그 클러스터 내에서만 검색을 수행하여 검색 속도를 크게 향상시킵니다.

3. 인덱스 유형에 따른 속도 비교 (FlatL2, PQ, IVFPQ)

FAISS에서는 다양한 인덱스 유형을 제공하며, 각 인덱스 유형은 속도와 정확도 측면에서 차이가 있습니다.

  • IndexFlatL2:
    • 특징: 벡터 간의 유클리드 거리(L2)를 기반으로 한 완전한 인덱스입니다.
    • 속도: 느리지만, 정확도가 가장 높습니다. 모든 벡터를 비교하므로 시간이 많이 걸립니다.
index = faiss.IndexFlatL2(128)
index.add(vectors)
  • IndexIVFFlat:
    • 특징: 벡터를 클러스터링한 후, 클러스터 내에서 검색을 수행합니다. IVF 기반의 기본 인덱스입니다.
    • 속도: IndexFlatL2보다 빠르며, 검색 속도와 정확도 간의 균형이 좋습니다.
nlist = 100  # 클러스터 수
index = faiss.IndexIVFFlat(index, 128, nlist)
index.train(vectors)
index.add(vectors)
  • IndexPQ (Product Quantization):
    • 특징: 벡터를 여러 개의 하위 벡터로 나눈 후, 각 하위 벡터를 별도로 양자화하여 검색 효율을 높입니다.
    • 속도: 매우 빠르며, 메모리 사용량이 적습니다. 그러나 정확도는 다소 떨어질 수 있습니다.
m = 8  # 하위 벡터 수
index = faiss.IndexPQ(128, m, 8)
index.train(vectors)
index.add(vectors)
  • IndexIVFPQ:
    • 특징: IVF와 PQ를 결합하여 클러스터링된 벡터들에 대해 양자화를 수행합니다. 대규모 데이터셋에서 빠르고 효율적인 검색을 가능하게 합니다.
    • 속도: 매우 빠르며, 적절한 정확도를 유지할 수 있습니다.
nlist = 100  # 클러스터 수
m = 8  # 하위 벡터 수
index = faiss.IndexIVFPQ(128, nlist, m, 8)
index.train(vectors)
index.add(vectors)

속도 비교:

  • IndexFlatL2는 모든 벡터를 직접 비교하므로 가장 느리지만, 정확도가 가장 높습니다.
  • IndexIVFFlat는 클러스터 기반 검색으로 속도가 빠르지만, 클러스터의 수(nlist)에 따라 정확도가 달라질 수 있습니다.
  • IndexPQ는 메모리 효율성을 위해 양자화를 사용하며, 속도가 매우 빠르지만 정확도는 다소 떨어질 수 있습니다.
  • IndexIVFPQ는 IVF와 PQ의 장점을 결합하여 대규모 데이터셋에서 빠르고 효율적인 검색을 제공합니다.

Ranking의 필요성과 해결 방법

1. Ranking이 필요한 이유

벡터 검색의 결과로 반환된 벡터들은 유사도 기준으로 정렬됩니다. 그러나 단순히 유사도가 높은 벡터들만을 보여주는 것은 때로는 사용자가 원하는 결과를 얻는 데 충분하지 않을 수 있습니다. 예를 들어, 검색 결과가 모두 비슷한 내용일 경우 다양성이 부족하여 유용하지 않을 수 있습니다. 따라서, 검색 결과를 정렬하고 다양한 정보를 제공하기 위해 Ranking 알고리즘이 필요합니다.

2. Ranking의 해결 방법

Ranking을 개선하기 위한 여러 가지 방법이 있습니다:

  • MMR 적용: 앞서 설명한 MMR(Maximal Marginal Relevance) 알고리즘을 사용하여 유사도와 다양성을 동시에 고려한 결과를 제공할 수 있습니다.
  • Re-ranking: 검색된 결과를 초기 유사도 기준으로 정렬한 후, 추가적인 필터링이나 정렬 기준(예: 최신성, 평점 등)을 적용하여 재정렬할 수 있습니다.
  • 사용자 피드백 기반 학습: 사용자의 클릭이나 행동 데이터를 활용하여 개인화된 Ranking 모델을 학습시키고, 사용자의 의도에 맞는 결과를 우선적으로 보여줄 수 있습니다.

결론

벡터 검색은 현대 정보 검색 시스템에서 필수적인 기술로, 특히 대규모 데이터셋에서 유사도 검색과 MMR 알고리즘을 통해 검색 결과의 정확성과 다양성을 크게 향상시킬 수 있습니다. FAISS를 사용하면 다양한 인덱스 유형을 통해 효율적인 벡터 검색을 구현할 수 있으며, 검색 속도와 정확도 간의 균형을 맞출 수 있습니다. Ranking 알고리즘을 적절하게 활용하면, 단순히 유사도가 높은 결과뿐만 아니라 사용자가 필요로 하는 다양한 정보를 제공할 수 있습니다.

반응형

'RAG' 카테고리의 다른 글

RAG를 활용한 LLM 추론 파이프라인 이해와 실습 [9]  (1) 2024.09.07
RAG 고려사항 [8]  (7) 2024.09.02
RAG 벡터 데이터베이스 [6]  (4) 2024.08.31
RAG 검색 방법 [5]  (0) 2024.08.31
RAG 검색 [4]  (1) 2024.08.30