Facebookの研究 効率的な類似検索のためのライブラリ

伝統的なクエリの検索エンジンは、短い秋の挑戦 - 今月、我々はFacebookのAI類似検索(Faiss)、私たちはすぐに互いに類似しているマルチメディア・ドキュメントを検索することを可能にするライブラリをリリースしました。我々はいくつかの8.5より速く、以前報告された最先端の、文献で知られているGPU上で最速のk-選択アルゴリズムとともによりも億規模なデータセットの最近傍検索の実装を構築しました。これは、私たちは10億高次元ベクトルで構成された第1のk最近傍グラフを含むいくつかのレコードを破ることができます。

類似検索について
従来のデータベースは、シンボリック情報を含む構造のテーブルで構成されています。例えば、画像コレクションは、索引付けされた写真ごとに1つの行を有するテーブルとして表現されることになります。各行は、画像識別子及び説明テキストなどの情報を含んでいます。行は、そのような名前のテーブルにリンクされていることで人とのイメージとして、同様に他のテーブルからエントリにリンクすることができます。

テキスト埋め込み(word2vec)または深い学習と訓練を受けた畳み込みニューラルネット(CNN)記述子のようなAIツールは、高次元のベクトルを生成します。私たちは、この記事で説明しますように、これらの表現は、固定記号表現よりもはるかに強力かつ柔軟です。しかし、SQLを使用して照会することができ、従来のデータベースは、これらの新しい表現に適応されていません。まず、新しいマルチメディアアイテムの巨大な流入は、ベクトルの十億を作成します。第二に、そしてもっと重要なことは、類似したエントリを見つけることは、標準のクエリ言語では不可能ではない場合は非効率的である同様の高次元のベクトルを、見つけることを意味します。

ベクトル表現をどのように使用することができますか?
たとえば、名前を忘れてしまった、いくつかの中規模都市の市役所 - - あなたは、画像コレクションのこの建物の他のすべての画像を検索したいし、あなたが建物のイメージを持っているとしましょう。通常、SQLで使用されているキー/値のクエリは、都市の名前を忘れてしまったので、助けにはなりません。

これは、画像のためのベクトル表現を、類似のベクターユークリッド空間に近くであるものとして定義される類似画像のための類似のベクターを生成するように設計されている。ここで類似検索キックです。

ベクトル表現の別の用途は、分類です。あなたは、コレクション内の画像は、デイジーを表現するかを決定分類器を必要と想像してみてください。分類器を訓練することは周知のプロセスである:アルゴリズムは、非ヒナギクヒナギクと画像の入力画像(車、ヒツジ、バラ、たcornflowers)として取ります。分類器は線形であるならば、それは、その財産画像ベクトルとの内積が、それは画像がデイジーが含まれていることをどのように可能性が反映していることである分類ベクトルを出力します。そして、内積は、コレクション内のすべてのエントリを計算することができ、最高値を持つ画像が返されます。クエリのこのタイプは、「最大の内積」検索です。

だから、類似検索と分類のために、我々は次の操作が必要になります。

クエリベクトルを考えると、ユークリッド距離の面で、このベクトルに最も近いデータベースオブジェクトのリストを返します。
クエリベクトルを考えると、このベクターでの最高の内積を持つデータベースオブジェクトのリストを返します。
追加の課題は、ベクトルの十億に、我々は大規模にこれらの操作をしたいということです。

ソフトウェアパッケージ
現在利用可能なソフトウェアツールは、上記のデータベース検索操作のために十分ではありません。それらは、ハッシュベースの検索や1D間隔検索用に最適化されているので、従来のSQLデータベースシステムが実用的ではありません。「小さな」データセット(例えば、唯一の100万ベクトル)を考慮し、他の類似検索ライブラリですとOpenCVのようなパッケージで提供されている類似検索機能は、スケーラビリティの面で厳しく制限されています。他のパッケージには、特定の設定でパフォーマンスを発揮するために発表された論文のために生産の研究成果物です。


Faissで、我々は、上記の制限に対処ライブラリをご紹介します。その利点の中で:

Faissは、使用トレードオフの広範囲に及ぶいくつかの類似性検索方法を提供します。
Faissは、メモリ使用量と速度のために最適化されています。
Faissは、最も関連性の高いインデックスメソッドのための最先端のGPUの実装を提供しています。
類似検索の評価
ベクトルは(他の場所の画像、動画、テキスト文書、およびから)機械を学習することによって抽出されると、彼らは類似検索ライブラリーに供給する準備が整いました。

正確かつ徹底的に - - 私たちはすべての類似度を計算し、参照ブルートフォースアルゴリズムを持っており、最も類似した要素のリストを返します。これは、「ゴールドスタンダード」参照結果のリストを提供します。効率的にブルートフォースアルゴリズムを実装する明白ではない、そしてそれは多くの場合、他のコンポーネントのパフォーマンスに供給することに注意してください。

我々はいくつかの精度を交換して喜んでいる場合は類似検索は桁違いに高速化することができます。つまり、参照結果から少しずれます。画像の類似検索の第一および第二の結果が入れ替わっている場合、彼らはおそらく特定のクエリのための両方正しい結果ですので、例えば、それは、あまり重要ではないかもしれません。検索を加速することで、データセットのいくつかの前処理、我々はインデックス作成を呼び出す操作を必要とします。

これは、3つの関心メトリクスに私たちをもたらします:

速度。どのくらいの時間が10(または他の数)のクエリに最も類似したベクトルを見つけるために時間がかかりますか?ブルートフォースアルゴリズムのニーズよりもうまくいけば、少ない時間。それ以外の場合は、インデックスのポイントは何ですか?
メモリ使用量。この方法は、どのくらいのRAMを必要としていますか?より多くのまたは元のベクターよりも小さいですか?Faissは、ディスクのデータベースが遅く桁違いあるとして、RAMからのみ検索をサポートしています。はい、でもSSDを持ちます。
正確さ。どれだけの結果を返されたリストは、力まかせ探索結果と一致していますか?精度は、真の最近傍点が最初結果リスト(1 @ 1リコールと呼ばれる尺度)で、又は10に戻される10の最近傍の平均割合を測定することによって返されるのクエリの数をカウントすることによって評価することができます最初の結果(「10-交差点」測定)。
我々は通常のトレードオフの速度と精度との間の固定されたメモリ使用量についての評価します。彼らはベクトルの数十億のデータセットに拡張だけのものだからFaissは、元のベクトルを圧縮する方法に焦点を当て:10億個のベクトルがインデックス化されなければならないとき、ベクターあたり32のバイトが大量のメモリを占有します。

多くのインデックスライブラリは、我々は小さな規模を呼び出す周りに100万のベクトル、のために存在します。例えば、nmslibは、このために非常に効率的なアルゴリズムが含まれています。それはFaissよりも高速ですが、かなり多くのストレージを必要とします。

10億個のベクトルの評価
エンジニアリングの世界は、このサイズのデータ​​セットのための十分に確立ベンチマークを持っていないので、我々は研究結果と比較します。

精度が上で評価されDeep1B、10億枚の画像のコレクション。各画像は、畳み込みニューラルネットワーク(CNN)によって処理されており、CNNの活性化マップの一つが画像記述子として保持されます。これらのベクターは、画像がどの程度似ているかを定量化するためにユークリッド距離と比較することができます。

Deep1Bは、クエリ画像の小さなコレクションが付属しており、地上真実類似検索結果は、これらの画像上のブルートフォースアルゴリズムから提供されています。我々は、検索アルゴリズムを実行する場合したがって、我々は結果の1 @ 1-リコールを評価することができます。

インデックスを選択します
評価のために、我々は、RAMの30ギガバイトのメモリ使用量を制限します。このメモリ制約は、インデックスメソッドとパラメータの我々の選択を案内します。Faissでは、索引付け方法は、文字列として表されます。この場合、OPQ20_80、IMI2x14、PQ20。

文字列は、データベースが分割されるべきかを示す選択機構(IMI2x14)、ベクトルに適用する前処理工程(OPQ20_80)を示し、符号化成分(PQ20)ベクターは、製品量子化器(PQ)で符号化されることを示しますそれは、20バイトコードを生成します。したがって、メモリ使用量は、オーバーヘッドを含む、RAMの30ギガバイト未満です。

我々は、これは少し技術的な音を知っている、とFaissのドキュメントが最良のあなたのニーズに適応したインデックスを選択する方法のガイドラインを提供理由です。

インデックス・タイプが選択されると、インデックス作成を開始することができます。このアルゴリズムは、10億個のベクトルを処理し、インデックスにそれらを置きます。インデックスは、ディスクに格納されているか、すぐに使用し、インデックスへの検索や追加/削除をインターリーブすることができますすることができます。

インデックスでの検索
インデックスの準備ができたら、検索時パラメータのセットは、方法を調整するように設定することができます。評価のために、我々は、単一のスレッド内で検索を実行します。ここでは、メモリ使用量が固定されているため、精度の間のトレードオフを最適化し、時間を検索する必要があります。これは最低限の検索時間で40%の1 @ 1-リコールを与えるパラメータを設定することができること、例えば、意味しています。

幸い、Faissは、パラメータのスペースをスキャンして、最高の動作点を提供するものを収集し、自動チューニング・メカニズムが付属しています。それは、いくつかの精度、およびその逆を与えられた可能な限り最高の検索時間です。Deep1Bでは、動作点がプロットとして視覚化することができます。


このプロットでは、我々は1〜40の割合@ 1-リコールを得ることはベクトルあたり2ミリ秒未満のクエリ時間を持っていることを読んで、または0.5ミリ秒の時間予算で、我々は30%に達することができることができます。2ミリ秒のクエリ時間は、単一のコア上で毎秒500個のクエリ(QPS)に変換します。

この結果は、フィールドでの最先端の研究結果から得られた結果と比較することができます:「ディープ記述子の10億規模データセットの効率的な索引付け BabenkoとLempitsky、CVPR 2016、Deep1Bデータセットを導入することにより、用紙を」。彼らは、45%の1-リコール@ 1を得るために、20ミリ秒を必要としています。

GPUを搭載した十億規模なデータセット
多くの労力が入ったGPUの実装ネイティブのマルチGPUサポートと驚異的な単一マシンのパフォーマンスを得。GPUの実装はまた、CPU同等物の代わりにドロップされ、あなたはのGPUを活用するために、CUDAのAPIを知っている必要はありません。GPU Faiss 2012(ケプラー、計算機能3.5+)の後に導入されたすべてのNvidiaGPUをサポートしています。

私たちは、使用したいルーフラインのモデルを 1は、メモリ帯域幅浮動小数点ユニットを飽和させるために努力すべきであると述べているガイドとして。Faiss GPUは、典型的には、対応するFaissのCPUの実装よりも、単一のGPU上で高速5-10xれます。新パスカルクラスのハードウェアは、P100のように、20倍+にこれをプッシュします。

いくつかの印象的な数字:

近似インデックス付けと、の9500万画像の128D CNNディスクリプタブルートフォースのk最近傍グラフ(K = 10)YFCC100Mの 0.8の10交差点で設定されたデータは、4つのマクスウェルタイタンXのGPU上で35分で構築することができます、インデックス構築時間を含みます。
億ベクトルのk最近傍グラフを簡単に手の届くところになりました。一つは、8パスカルP100-のPCIeで12時間の下の4基のマクスウェルタイタンXのGPU、または0.8に、12時間の下で0.65の10交差点で設定Deep1BデータのブルートフォースK-NNグラフ(K = 10)を作ることができますGPU。低品質のグラフはタイタンX構成で5時間の下で製造することができます。
他の構成要素は、印象的なパフォーマンスを実現します。例えば、Deep1Bインデックス上に構築する25回のEMの反復のために上の4つのタイタンXのGPU上で139分(計算の12.6 tflop /秒)、または43.8分262,144重心に6710万120次元のベクトルをk-meansクラスタリングを必要とします8つのP100のGPU(コンピューティングの40 tflop /秒)。クラスタリングのトレーニングセットは、パフォーマンスに影響を与えることなく、必要に応じてデータをGPUにストリーミングされるように、GPUメモリに収まるようにする必要はありません。
フードの下
FacebookのAI研究チームは研究成果とかなりのエンジニアリング作業に基づいて、2015年にFaissの開発に着手しました。このライブラリのために、我々はいくつかの基本的な技術の適切最適化されたバージョンに焦点を当てることにしました。具体的には、CPU側で、私たちは頻繁に使用します

マルチスレッド、複数のコアを活用し、複数のGPUで並列検索を実行します。
BLASの行列/行列乗算を介して効率的に正確な距離計算のためのライブラリ。効率的なブルートフォースの実装は、BLASを使用せずに最適にすることはできません。BLAS / LAPACKはFaissの唯一の必須ソフトウェア依存関係です。
マシンのSIMDベクトル化とPOPCOUNTは孤立ベクトルの距離計算を高速化するために使用されています。
GPU側で
類似検索の以前のGPU実装のために、K-選択(K-最小または最大の要素を見つけるには)優しいGPUされていない(例えば、ヒープ選択)は、典型的なCPUアルゴリズムとして、パフォーマンスの問題となっていました。Faiss GPUのために、我々は、文献で知られている最速の小K-選択アルゴリズム(K <= 1024)を設計しました。すべての中間状態は、その高速に貢献し、レジスタに完全に保たれています。K-選択するピークGPUメモリ帯域幅によって与えられるように、ピークのパフォーマンスの最大55%で動作するシングルパスで入力データを、可能です。その状態は、レジスタファイルにのみ保持されているので、それが燃える高速正確な近似検索アルゴリズムに自分自身を貸し、他のカーネルとヒュージブルです。

注目は、効率的なタイリング戦略とおおよその検索に使用するカーネルの実装に支払われました。マルチGPUサポートはシャーディング又は複製データのいずれかによって提供されます。1はシングルGPUで使用可能なメモリに限定されるものではありません。半精度浮動小数点サポート(float16)は支持のGPUおよびそれ以前のアーキテクチャ上に設けられた中間float16ストレージに完全float16の計算を用いて、同様に提供されます。私たちは、float16の利回りとしてコードするベクターは、精度のほとんどを失うことなく高速化することを発見しました。

要するに、一定のオーバーヘッドの要因は、実装には問題。Faissは、エンジニアリングの詳細に注意を払うの痛みを伴う作業の多くをしました。

やってみて
FaissはC ++で実装し、Pythonでのバインディングを持っています。開始するには、それをコンパイルし、GitHubのからFaissを取得し、とPythonにFaissモジュールをインポートします。Faissはnumpyのと完全に統合され、そして全ての機能は、(のfloat32に)numpyの配列を取ります。

インデックスオブジェクト
Faiss(C ++とPythonの両方)のインスタンスを提供しますIndex。各Indexサブクラスはベクトルを添加し、検索可能なインデックス構造を実現します。例えば、IndexFlatL2L2の距離と検索ブルートフォースインデックスです。

輸入faissの                    #はfaiss利用できるようにする
インデックス= faissを。IndexFlatL2 (D )#は、ベクトルのインデックス、D =サイズ構築ここではXBは、n-によって-Dタイプのfloat32のnumpyの行列含まれていると#を
インデックスを。追加(XB )#は、インデックスにベクトルを追加し、印刷インデックス。NTOTAL   


                  
これは、インデックス付きのベクトルの数が表示されます。追加すると、IndexFlatベクトルに適用されていない処理がないのでちょうど、インデックスの内部ストレージにコピーします。

検索を実行するには:

#1 XQは、クエリとN2-によって-Dマトリックスは、ベクトルされ
、K = 4 #私たちは4つの同様のベクターたい
D 、I = インデックスを。検索(XQ 、K )#実際の検索印刷I                                
私は整数行列です。出力は次のようなものです:

[[  0 393 363  78]
 [  1 555 277 364]
 [  2 304 101  13]]
 
最初のベクトルに対してxq、最も類似するベクトルのインデックスがxb、同様のほとんどの第二の#393であり、第三のように#363であり、そして(0系)0です。第二のベクトルについてxq、類似のベクターのリストはここで#1、#555、等であるが、最初の3つのベクトルは、xq最初の3と同じように見えますxb。

行列Dは、距離の二乗の行列です。それは私と同じ形状をしており、クエリの乗ユークリッド距離での各結果ベクトルのために示します。

Faissは、しばしば、他の指標の組成物であるダース・インデックス・タイプを実装します。オプションのGPUバージョンは全く同じインターフェースを有しており、CPUとGPUのインデックス間の変換するブリッジがあります。Pythonインタフェースは、主にC ++のインデックスを公開するためにC ++から生成されるので、統合C ++にPythonの検証コードを変換するのは簡単です。