Relative Score Fusion and Distribution-Based Score Fusion
Relative Score Fusion and Distribution-Based Score Fusion
Reciprocal Rank Fusion을 개선하기 위한 두 가지 퓨전 방법, Relative Score Fusion과 Distribution-Based Score Fusion을 QueryFusionRetriever로 사용하는 예시예요. 두 방법의 차이를 코드로 직접 비교해 볼게요.
출처: 문서
본문
이 예시에서는 Reciprocal Rank Fusion을 개선하려는 두 가지 방법으로 QueryFusionRetriever를 사용하는 방법을 보여줍니다:
- Relative Score Fusion (Weaviate)
- Distribution-Based Score Fusion (Mazzeschi: blog post)
%pip install llama-index-llms-openai
%pip install llama-index-retrievers-bm25
import os
import openai
os.environ["OPENAI_API_KEY"] = "sk-..."
openai.api_key = os.environ["OPENAI_API_KEY"]
Setup
이 노트북을 colab에서 여는 경우 LlamaIndex 🦙를 설치해야 할 수 있습니다.
데이터 다운로드
!mkdir -p 'data/paul_graham/'
!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/paul_graham/paul_graham_essay.txt'
from llama_index.core import SimpleDirectoryReader
documents = SimpleDirectoryReader("./data/paul_graham/").load_data()
다음으로 문서 위에 벡터 인덱스를 구성합니다.
from llama_index.core import VectorStoreIndex
from llama_index.core.node_parser import SentenceSplitter
splitter = SentenceSplitter(chunk_size=256)
index = VectorStoreIndex.from_documents(
documents, transformations=[splitter], show_progress=True
)
Relative Score Fusion을 사용한 Hybrid Fusion Retriever 생성
이 단계에서는 인덱스를 BM25 기반 리트리버와 융합합니다. 이렇게 하면 입력 쿼리에서 의미적 관계와 키워드를 모두 포착할 수 있습니다.
두 리트리버 모두 점수를 계산하므로, 추가 모델이나 과도한 계산 없이 QueryFusionRetriever를 사용해 노드를 재정렬할 수 있습니다.
다음 예시는 Weaviate의 Relative Score Fusion 알고리즘을 사용하는데, 각 결과 집합에 MinMax 스케일러를 적용한 뒤 가중 합을 만듭니다. 여기서는 벡터 리트리버에 BM25보다 약간 더 큰 가중치를 줍니다(0.6 대 0.4).
먼저 리트리버를 생성합니다. 각 리트리버는 가장 유사한 상위 10개 노드를 가져옵니다.
from llama_index.retrievers.bm25 import BM25Retriever
vector_retriever = index.as_retriever(similarity_top_k=5)
bm25_retriever = BM25Retriever.from_defaults(
docstore=index.docstore, similarity_top_k=10
)
다음으로 퓨전 리트리버를 만들 수 있는데, 이 리트리버는 리트리버들이 반환한 20개 노드 중 상위 10개를 반환합니다.
벡터와 BM25 리트리버가 동일한 노드를 서로 다른 순서로만 반환했을 수도 있으므로, 이 경우에는 단순히 재정렬기(re-ranker) 역할을 한다는 점에 주의하세요.
from llama_index.core.retrievers import QueryFusionRetriever
retriever = QueryFusionRetriever(
[vector_retriever, bm25_retriever],
retriever_weights=[0.6, 0.4],
similarity_top_k=10,
num_queries=1, # set this to 1 to disable query generation
mode="relative_score",
use_async=True,
verbose=True,
)
# apply nested async to run in a notebook
import nest_asyncio
nest_asyncio.apply()
nodes_with_scores = retriever.retrieve(
"What happened at Interleafe and Viaweb?"
)
for node in nodes_with_scores:
print(f"Score: {node.score:.2f} - {node.text[:100]}...\n-----")
Distribution-Based Score Fusion
Relative Score Fusion의 변형으로, Distribution-Based Score Fusion은 각 결과 집합의 점수 평균과 표준편차에 기반해 점수를 조금 다르게 스케일링합니다.
from llama_index.core.retrievers import QueryFusionRetriever
retriever = QueryFusionRetriever(
[vector_retriever, bm25_retriever],
retriever_weights=[0.6, 0.4],
similarity_top_k=10,
num_queries=1, # set this to 1 to disable query generation
mode="dist_based_score",
use_async=True,
verbose=True,
)
nodes_with_scores = retriever.retrieve(
"What happened at Interleafe and Viaweb?"
)
for node in nodes_with_scores:
print(f"Score: {node.score:.2f} - {node.text[:100]}...\n-----")
Query Engine에서 사용하기!
이제 리트리버를 쿼리 엔진에 연결해 자연어 응답을 합성할 수 있습니다.
from llama_index.core.query_engine import RetrieverQueryEngine
query_engine = RetrieverQueryEngine.from_args(retriever)
response = query_engine.query("What happened at Interleafe and Viaweb?")
from llama_index.core.response.notebook_utils import display_response
display_response(response)