メインコンテンツまでスキップ

「faiss」タグの記事が1件件あります

全てのタグを見る

Python FAISSでベクトル検索

· 約6分
Mikyan
白い柴犬
  • FAISSを使って高次元ベクトルの中から、クエリベクトルに最も「似ている」ベクトルを高速に検索できる
  • RAGにおいて、FAISSを使って、関連文書を検出ことができる

詳細

高次元の課題 (Curse of Dimensionality): 次元数が増えると(例えば、数千次元のベクトル)、ベクトル間の距離計算は非常に高コストになり、従来のデータベース手法では効率的に検索できなくなります。FAISSは、この高次元空間での非効率性を克服するための様々な工夫(近似検索アルゴリズム)を提供します。

類似性検索のニーズ: 「意味的に似ているものを探す」「内容が近い画像を見つける」「類似する推薦アイテムを提案する」といった、人間の直感的な「似ている」を数値データから見つけ出すニーズが、AI/MLの発展とともに爆発的に増加しました。FAISSは、このニーズに応えるための高速なソリューションです。

スケーラビリティ: データ量が膨大になっても、秒単位やミリ秒単位で検索結果を返すことが求められます。FAISSは、インデックス構造の工夫や並列処理、GPU活用などにより、このスケーラビリティを実現します。

FAISSは、基本的にメモリ内で高速な類似検索を行いますが、大規模なデータセットに対応するために、メモリ管理やストレージとの連携に関する様々な機能や戦略を持っています。

利用

FAISSのAPIは、大きく分けてインデックスの作成と検索の2つのフェーズで構成されます。

  1. インデックスの作成(Add / Train) まず、検索対象となるベクトルデータをFAISSのインデックス構造に「追加」します。
import faiss
import numpy as np

# 1. ベクトルデータの準備
# 例として、128次元のベクトルが1000個あると仮定
dimension = 128
num_vectors = 1000
data_vectors = np.random.rand(num_vectors, dimension).astype('float32')

# 2. インデックスの選択と初期化
# 最もシンプルなインデックス: IndexFlatL2
# L2 はユークリッド距離を意味し、最も厳密な(近似ではない)検索を行う
index = faiss.IndexFlatL2(dimension)

print(f"インデックスが空か?: {index.is_trained}") # IndexFlatL2は訓練不要なのでTrue
print(f"インデックスのベクトルの数: {index.ntotal}") # 初期状態では0

# 3. インデックスへのベクトルの追加
index.add(data_vectors)

print(f"インデックスのベクトルの数: {index.ntotal}") # 1000

faiss.IndexFlatL2(dimension): これは最も基本的なインデックスで、全てのベクトルをそのままメモリに格納し、クエリが来たら総当たりで距離を計算します(ブルートフォース検索)。L2 はユークリッド距離(二点間の直線距離)を意味します。これは厳密な最近傍探索を行いますが、データ量が増えると非常に遅くなります。

index.is_trained: インデックスによっては、データを追加する前に「訓練(train)」が必要なものがあります(例: IndexIVFFlat, IndexPQ)。これは、ベクトル空間を効率的に分割するためのクラスタリングなどを行います。IndexFlatL2 は訓練不要なので最初から True です。

index.add(vectors): 訓練が終わった(または不要な)インデックスに、実際にベクトルデータを追加します。

# 1. クエリベクトルの準備
# 例として、1つのクエリベクトルを準備
query_vector = np.random.rand(1, dimension).astype('float32') # 1つのクエリは (1, dimension) 形状

# 2. 検索の実行
# k=5: 最も近い5つのベクトルを検索
k = 5
distances, indices = index.search(query_vector, k)

print(f"検索されたベクトルのインデックス (元の data_vectors での): {indices}")
print(f"検索されたベクトルの距離: {distances}")

index.search(query_vectors, k):

query_vectors: 検索したいベクトル。複数個のクエリを一度に渡すことも可能です(例: (num_queries, dimension) のNumPy配列)。

k: 取得したい最近傍ベクトルの数。

戻り値:

distances: 検索された k 個のベクトルとクエリベクトルとの間の距離。

indices: 検索された k 個のベクトルが、インデックス追加時に持っていた元のインデックス(add したときの順番)を示します。

3. インデックスの保存とロード

作成したインデックスはファイルに保存し、後でロードして再利用できます。

# インデックスの保存
faiss.write_index(index, "my_faiss_index.bin")
print("インデックスを 'my_faiss_index.bin' に保存しました。")

# インデックスのロード
loaded_index = faiss.read_index("my_faiss_index.bin")
print(f"ロードされたインデックスのベクトルの数: {loaded_index.ntotal}")