🕌

FAISS の IVF+HNSWにおけるパラメーター推奨値

に公開

FAISS の IVF+HNSW (Inverted File with Hierarchical Navigable Small World) インデックスは、高次元ベクトルの近似最近傍検索(ANN: Approximate Nearest Neighbor Search)を高速化するための強力な手法です。
特に、検索精度と検索速度のバランスを取るために、以下のパラメーターを調整することが重要です。

調整可能なパラメーター

1. nlist(クラスタ数)

  • データセットを nlist 個のクラスタに分割する。
  • nlist が大きいほどクラスタは細かくなり、検索時の候補数が減るため検索速度は向上するが、適切なクラスタが選ばれないと精度が低下する。
  • 推奨値: sqrt(N), ただし N はデータセットのサイズ。

2. nprobe(検索するクラスタ数)

  • 検索時に探索するクラスタの数。
  • nprobe を大きくすると検索精度は向上するが、検索時間が増加する。
  • 推奨値: nlist の 1%〜10%。

3. efSearch(HNSW の検索用パラメータ)

  • HNSW の検索の際に考慮する候補数。
  • efSearch を大きくすると検索精度は向上するが、計算コストが増加する。
  • 推奨値: nprobe * 4 くらいが目安。

4. efConstruction(HNSW の構築用パラメータ)

  • HNSW グラフを構築する際の最大候補数。
  • efConstruction を大きくすると検索精度は向上するが、インデックス構築時間とメモリ消費が増加する。
  • 推奨値: 64〜256。

実際のコード例

以下のコードでは、IVF+HNSW を用いてベクトル検索を最適化する方法を示します。

1. インデックスの作成

import faiss
import numpy as np

# データセットの準備
d = 128  # ベクトルの次元
N = 100000  # データセットのサイズ
X = np.random.random((N, d)).astype('float32')  # ランダムなベクトルを生成

# パラメータ設定
nlist = int(np.sqrt(N))  # クラスタ数(IVFのパーティション数)
nprobe = max(1, nlist // 10)  # 検索時に探索するクラスタ数
efConstruction = 128  # HNSW の構築パラメータ
efSearch = nprobe * 4  # HNSW の検索パラメータ

# IVF+HNSW のインデックスを作成
quantizer = faiss.IndexHNSWFlat(d, 32)  # 32はHNSWの接続度
index = faiss.IndexIVFFlat(quantizer, d, nlist, faiss.METRIC_L2)

# HNSWの構築パラメータを設定
quantizer.hnsw.efConstruction = efConstruction

# インデックスをトレーニング
index.train(X)
index.add(X)

# HNSWの検索パラメータを設定
index.nprobe = nprobe
quantizer.hnsw.efSearch = efSearch

print(f"Index trained: {index.is_trained}, Total vectors: {index.ntotal}")

2. 検索時のパラメータ調整

# クエリデータの準備
query = np.random.random((1, d)).astype('float32')  # 1つのクエリ

# 検索時のパラメータ
index.nprobe = nprobe  # IVF の探索クラスタ数
quantizer.hnsw.efSearch = efSearch  # HNSW の探索候補数

# 近傍検索
k = 10  # 取得する近傍の数
distances, indices = index.search(query, k)

print("Nearest neighbors:", indices)
print("Distances:", distances)

パフォーマンスチューニングのポイント

  1. nlist を適切に設定

    • nlist が小さすぎると検索時間が増加し、大きすぎるとクラスタの分散が大きくなり精度が低下する。
    • 一般的に sqrt(N) くらいが良いバランス。
  2. nprobe を適切に調整

    • nprobe を大きくすると検索精度が向上するが、検索時間が増加する。
    • nprobe = nlist / 10 くらいから試し、必要に応じて調整。
  3. efConstruction を大きめに設定

    • HNSW の構築時に多くの候補を考慮すると、検索精度が向上する。
    • ただし、メモリ消費が増加するため 64〜256 の範囲で調整。
  4. efSearch を調整

    • efSearch を大きくすると検索精度が向上するが、速度が低下する。
    • nprobe * 4 くらいを基準にし、精度に応じて調整。
  5. マルチスレッド化

    • FAISS はマルチスレッドで動作するため、並列化のためにスレッド数を設定できる。
    faiss.omp_set_num_threads(4)  # 4スレッドを使用
    

まとめ

FAISS の IVF+HNSW を効果的に活用するためには、以下のパラメータを調整することが重要です。

パラメータ 役割 推奨値
nlist クラスタの数(大きいほど高速だが精度が低下) sqrt(N)
nprobe 探索するクラスタ数(大きいほど精度向上) nlist / 10
efConstruction HNSW のグラフ構築時の候補数 64〜256
efSearch HNSW の検索時の候補数 nprobe * 4

調整の指針

  • 検索精度を上げたいなら nprobeefSearch を増やす
  • 検索速度を上げたいなら nlist を増やして nprobe を減らす
  • メモリ制約がある場合は efConstruction を小さくする

このようにパラメータを調整することで、検索精度と速度のバランスを最適化できます。
実際のデータセットで試しながら、適切な値を見つけてみてください!

Discussion