HNSWグラフのノードに、float32ベクトル(約4,096バイト)ではなく量子化埋め込み(次元=1024で各約388バイト)を格納する、というベクトル・インデックス作成のアプローチを試しています。
重要な洞察は、乱交差直交(ランダム直交)回転の後にLloyd-Maxスカラー量子化で埋め込みを量子化すること(ZandiehらによるPolarQuantアプローチ、ICLR 2026)です。これにより、セントロイド同士の内積テーブルを事前計算できます(3ビットなら8x8=64個のfloat)。グラフ巡回中の距離計算は、1024回のfloat乗算+加算ではなく、1024回のテーブル参照になります。検索中に復号(デコンプレッション)は不要です。
次に、上位-k候補を復号して、最終結果のために厳密なコサイン類似度で再ランキングします。
ランダム埋め込みでの初期結果(次元=128、2Kベクトル、M=16): - rerankingありで recall@10 > 0.85(総当たり探索と比較) - ノードあたりのメモリ使用量:float32 HNSWより約4倍少ない - 構築は遅い(最適化なしのPythonプロトタイプ)
まだうまくいっていない点: - 距離における量子化ノイズによって、貪欲探索が最適でない経路をたどることがあり、その補償のためにより大きいef値が必要になる - ごく小さい次元(dim=64)では、近傍リストとキャッシュされたインデックスのオーバーヘッドが支配的なので、実際にはメモリ節約にならない - 構築時間が遅い -- PythonのHNSW実装は、構築速度の点でFAISSに対して競争力がない
面白い副発見: 圧縮された埋め込みキャッシュも構築する(ベクトルをパックされたワイヤ形式で保存する)と、同じRAM予算で約10倍の埋め込みを収められます。Zipf分布に従うアクセスパターンでは、キャッシュヒット率が100MBで約60%から約95%へ跳ね上がります。
回転+量子化のための融合CUDAカーネル(フロート32の中間生成物を書き出さずにインラインで量子化する、タイルドGEMM)もまたうまくいきました。これにより、N*dimのフロート32のラウンドトリップをグローバルメモリに対して1回分まるごと削除できます。
復号なしで、量子化された表現のままANNインデックスを直接操作することを、他の方は試されていますか? 標準的なPQ(プロダクト量子化)以外のアプローチについても知りたいです。PQはサブベクトルに対して動作し、スカラー量子化された“完全なベクトル”ではないからです。
コードは https://github.com/ahb-sjsu/turboquant-pro にあります。見てみたい方はどうぞ。。
[link] [comments]




