FAISS(Facebook AI Similarity Search)は、密なベクトルの効率的な類似検索とクラスタリングのための強力なライブラリです。その主な機能の1つは、類似検索を実行し、類似したベクトルだけでなく、各結果がクエリにどれだけ類似しているかを示すスコアを返す能力です。この機能は、similarity_search_with_score
メソッドにカプセル化されています。この記事では、これらのスコアの意味、計算方法、およびアプリケーションでの解釈方法について詳しく説明します。
Anakin AIを使用して、コーディング知識なしでAIワークフローを簡単に作成できます。GPT-4、Claude 3.5 Sonnet、Uncensored Dolphin-Mixtral、Stable Diffusion、DALLE、Web ScrapingなどのLLM APIに接続して、ワークフローを1つにまとめます!
複雑なコーディングを忘れて、Anakin AIで日常的な作業を自動化しましょう!
期間限定で、Google Gemini 1.5とStable Diffusionも無料で使用できます!
![Anakin AIでAIエージェントのワークフローを簡単に作成してください!](https://assets.anakin.ai/blog/2024/07/anakin-2-3.webp)
ベクトルの類似度の基本
FAISSのスコアリングメカニズムの詳細に入る前に、ベクトルの類似度の基本的な概念を理解することが重要です。機械学習や情報検索の文脈では、データポイントは高次元ベクトルとして表現されることがよくあります。これらのベクトル間の類似度は、さまざまな距離尺度を使用して測定することができます。
FAISSで使用される2つの最も一般的な距離尺度は次のとおりです:
- L2(ユークリッド)距離
- 内積(ドット積)
距離尺度の選択は、使用している具体的なインデックスタイプとデータの性質に依存します。
FAISSインデックスタイプと距離尺度
FAISSは、検索速度と精度のトレードオフを考慮したさまざまなシナリオに最適化された複数のインデックスタイプを提供しています。一部の一般的なインデックスタイプには次のものがあります:
- IndexFlatL2:L2距離を使用した正確な検索
- IndexFlatIP:内積を使用した正確な検索
- IndexIVFFlat:反転ファイル構造を使用した近似検索
- IndexHNSWFlat:階層的ナビゲーション可能な小さな世界のグラフベースのインデックス
インデックスが使用する距離尺度は、通常、その名前に表示されます(例:ユークリッド距離のL2、内積のIP)。
similarity_search_with_score
メソッド
similarity_search_with_score
メソッドは、LangChainなどのライブラリのFAISSラッパーが提供する強力なツールです。これを使用すると、類似性検索を実行し、類似したベクトルとそれに対応する類似度スコアを取得することができます。
以下は、このメソッドの基本的な使用例です:
from langchain.vectorstores import FAISS
from langchain.embeddings import HuggingFaceEmbeddings
# ベクトル埋め込みを初期化し、FAISSインデックスを作成
embeddings = HuggingFaceEmbeddings()
db = FAISS.from_texts(["こんにちは、世界", "さようなら、世界"], embeddings)
# スコア付きの類似検索を実行
query = "こんにちは、地球"
results = db.similarity_search_with_score(query, k=2)
for doc, score in results:
print(f"内容:{doc.page_content}、スコア:{score}")
スコアの理解
similarity_search_with_score
が返すスコアの解釈は、FAISSインデックスで使用される基になる距離尺度に依存します。このスコアを解釈する方法を2つの主要な距離尺度について説明しましょう:
L2距離スコア
L2ベースのインデックス(IndexFlatL2など)を使用する場合、スコアはクエリベクトルと結果ベクトル間のユークリッド距離を表します。この場合:
- 低いスコアは高い類似度を示します
- スコアが0の場合、ベクトルは同一であることを意味します
- 最大スコアは、ベクトルの次元とスケールに依存します
これらのスコアは正規化されていないため、データによってはその絶対値が大きく異なる場合があります。
内積スコア
内積を使用するインデックス(IndexFlatIPなど)の場合、スコアはクエリベクトルと結果ベクトルの内積を表します。この場合:
- 高いスコアは高い類似度を示します
- ベクトルが同じ方向を指している場合に最大スコアが得られます
- スコアは正または負の値になります
ベクトルが正規化されている場合(つまり、大きさが1である場合)、内積はcos類似度に相当し、範囲は-1から1です。
スコアの正規化と解釈
FAISSからの生のスコアは直接解釈するのが難しい場合があります。特に異なるクエリやデータセット間で、それらのスコアを正確に比較することはしばしば役立ちます。次に、いくつかのアプローチを示します:
- Min-Max正規化:
スコアを結果セット内の最小スコアと最大スコアに基づいて範囲[0, 1]にスケーリングします。
def normalize_scores(scores):
min_score = min(scores)
max_score = max(scores)
return [(score - min_score) / (max_score - min_score) for score in scores]
- Softmax正規化:
スコアを確率に変換するためにソフトマックス関数を適用します。
import numpy as np
def softmax_normalize(scores):
exp_scores = np.exp(scores)
return exp_scores / np.sum(exp_scores)
- 相対スコアリング:
スコアを結果セット内の最良のスコアと比較します。
def relative_scores(scores):
best_score = max(scores)
return [score / best_score for score in scores]
実践的な考慮事項
similarity_search_with_score
を使用する際には、次の点に注意してください:
スコアの閾値:アプリケーションに応じて、スコアの閾値を設定して、関連性の低い結果をフィルタリングすることがあるかもしれません。この閾値は、特定のユースケースとデータセット内のスコアの分布に依存します。
異なるクエリ間での一貫性:1つのクエリのスコアは、別のクエリのスコアと直接比較できない場合があります。異なるクエリ間で結果を比較する必要がある場合は、一貫性のある正規化メソッドを使用することを検討してください。
ベクトルの正規化の影響:インデックス作成前にベクトルを正規化する場合(cos類似度の場合に一般的)、スコアの解釈に影響を与えます。正規化されたベクトルの場合、L2距離と内積スコアはより直接的に関連付けられるようになります。
インデックスパラメーター:インデックスタイプとそのパラメーター(IVFインデックスのクラスタ数など)の選択は、検索結果の精度とスコアの分布の両方に影響を与える可能性があります。
高度なテクニック
より高度なアプリケーションには、次のテクニックを考慮してください:
- マルチクエリ展開:
複数の関連するクエリを使用し、結果を集約することで検索品質を向上させます。
def multi_query_search(db, queries, k=5):
all_results = []
for query in queries:
results = db.similarity_search_with_score(query, k=k)
all_results.extend(results)
# 結果を集約して重複を削除
deduplicated = {}
for doc, score in all_results:
if doc.page_content not in deduplicated or score > deduplicated[doc.page_content][1]:
deduplicated[doc.page_content] = (doc, score)
return sorted(deduplicated.values(), key=lambda x: x[1], reverse=True)[:k]
- 再ランキング:
初期の高速検索のトップ結果を再ランクするために、より計算コストがかかるが正確なメソッドを使用します。
from sentence_transformers import CrossEncoder
def rerank_results(query, results, model_name='cross-encoder/ms-marco-MiniLM-L-6-v2'):
reranker = CrossEncoder(model_name)
pairs = [[query, doc.page_content] for doc, _ in results]
scores = reranker.predict(pairs)
reranked = sorted(zip(results, scores), key=lambda x: x[1], reverse=True)
return [(doc, new_score) for (doc, _), new_score in reranked]
- アンサンブルメソッド:
複数のインデックスタイプや埋め込みモデルの結果を組み合わせて堅牢性を向上させます。
def ensemble_search(query, indexes, weights=None):
if weights is None:
weights = [1] * len(indexes)
all_results = []
for idx, (index, weight) in enumerate(zip(indexes, weights)):
results = index.similarity_search_with_score(query, k=10)
all_results.extend((doc, score * weight, idx) for doc, score in results)
# 重複するドキュメントのスコアを集計
aggregated = {}
for doc, score, idx in all_results:
key = doc.page_content
if key not in aggregated:
aggregated[key] = [0] * len(indexes)
aggregated[key][idx] += score
# 最終的なスコアを計算してソート
final_results = [(doc, sum(scores)) for doc, scores in aggregated.items()]
return sorted(final_results, key=lambda x: x[1], reverse=True)
結論
FAISSのsimilarity_search_with_score
メソッドは、類似したベクトルを見つけ、それらの類似度の度合いを理解するための強力なツールです。これらのスコアがどのように計算され、解釈されるかを理解することで、ベクトルの類似性に依存するレコメンデーションシステム、シマンティックサーチエンジン、または他のアプリケーションをより効果的に構築することができます。
ベクトルの類似性検索の効果は、FAISSインデックスとスコアリングメカニズムだけでなく、ベクトル埋め込みの品質と関連性も考慮する必要があります。システムを最適化する際には、データの準備と埋め込み生成からインデックスの構築と類似性検索まで、パイプライン全体を考慮してください。
FAISSと類似度スコアで作業する際には、さまざまなインデックスタイプ、距離尺度、およびスコアの正規化手法を実験してみることを躊躇しないでください。最適なアプローチは、特定のユースケース、データの特性、パフォーマンス要件に依存します。FAISSが類似性スコアをどのように計算し、返すのかについて深く理解することで、洗練された効果的なベクトル検索アプリケーションを構築する準備が整います。
FAQ
Q:FAISSは、利用可能なRAMに収まらない大規模なデータセットをどのように処理しますか?
A:FAISSは、ディスクベースのインデックスとメモリマップされたI/Oを使用して、利用可能なRAMよりも大きなデータセットを効率的に処理します。これにより、巨大なベクトルコレクションでのスケーラブルな類似検索が可能になります。
Q:FAISSの類似検索の実用的な応用例は何ですか?
A:FAISSの類似検索は、レコメンデーションシステム、画像および音声検索、重複検出、およびシマンティックサーチエンジンなどで広く使用され、大規模なデータセット内の類似アイテムの高速かつ正確な検索を可能にします。
Q:FAISS GPU版とCPU版の違いを説明できますか?
A:FAISS GPU版は、グラフィックスカードの並列処理能力を利用してインデックスの構築および検索操作をより高速化する一方、CPU版はより汎用的で特別なハードウェアを必要としません。
Q:FAISSはどのように類似度スコアを計算しますか?
A:FAISSは、クエリベクトルとインデックスされたベクトル間の選択した距離尺度(例えば、L2距離または内積)に基づいて類似度スコアを計算します。スコアの解釈は、使用される具体的なインデックスタイプに依存します。
Q:FAISS類似検索でよく遭遇する問題は何ですか?
A:類似検索の速度と精度のトレードオフ、高次元データの処理の課題、注意深いパラメータの調整の必要性、およびクエリとインデックスされたアイテム間の一貫したベクトル正規化の確保などが一般的な問題です。