私はチャットボットを構築しているので、Word2Vecを使用してユーザーの入力をベクトル化する必要があります。
私は、Googleによる300万語(GoogleNews-vectors-negative300)の事前学習済みモデルを使用しています。
そこで、Gensimを使用してモデルをロードします。
import gensim
model = gensim.models.KeyedVectors.load_Word2vec_format('GoogleNews-vectors-negative300.bin', binary=True)
問題は、モデルのロードに約2分かかることです。ユーザーをそれほど長く待たせることはできません。
ロード時間を短縮するために何ができますか?
300万語のそれぞれとそれに対応するベクトルをMongoDBデータベースに入れることを考えました。それは確かに物事をスピードアップしますが、直感はそれが良いアイデアではないことを教えてくれます。
最新のgensimバージョンでは、オプションのlimit
パラメーターをload_Word2vec_format()
に使用して、ファイルの先頭からサブセットをロードできます。 (GoogleNewsのベクトルは、おおよそ最も頻度の低い順序にあるように見えるため、最初のNは通常、希望するNサイズのサブセットです。したがって、_limit=500000
_を使用して、最も頻度の高い500,000ワードのベクトルを取得します–かなり大きな語彙–メモリー/ロード時間の5/6を節約。
それで少し助けになるかもしれません。ただし、Webリクエストごとにリロードする場合は、ロードのIOバインド速度、および各リロードを保存する冗長メモリオーバーヘッドの影響を受けます。
組み合わせて使用すると役立ついくつかのトリックがあります。
元のWord2vec.cで作成された形式でこのようなベクターを読み込んだ後、gensimのネイティブsave()
を使用してそれらを再保存できることに注意してください。圧縮せずに保存し、バッキング配列が十分に大きい(そしてGoogleNewsセットが十分に大きい)場合、バッキング配列は生のバイナリ形式で別のファイルにダンプされます。そのファイルは、gensimのネイティブ[load(filename, mmap='r')][1]
オプションを使用して、後でディスクからメモリマップできます。
最初は、これにより負荷が急になります。ディスクからすべてのアレイを読み取るのではなく、OSは仮想アドレス領域をディスクデータにマッピングするだけなので、しばらくしてコードがそれらのメモリ位置にアクセスすると必要な範囲が読み取られます-ディスクから。ここまでは順調ですね!
ただし、most_similar()
のような一般的な操作を実行している場合は、少し遅れて大きな遅れに直面することになります。これは、この操作には、すべてのベクトルに対する最初のスキャンと計算(最初の呼び出しで、すべてのWordに対して単位長正規化ベクトルを作成するため)と、すべての標準ベクトルに対する別のスキャンと計算の両方(呼び出しごとに、最も類似したN個のベクトルを見つけます)。これらのフルスキャンアクセスは、アレイ全体をRAMにページインします。これも、数分のディスクIOのコストがかかります。
あなたが望むのは、そのユニット正規化を重複して行うことを避け、IOコストを一度だけ支払うことです。これは、後続のすべてのWebリクエストで再利用するためにベクトルをメモリに保持する必要があります幸いなことに、いくつかの追加の準備手順がありますが、メモリマッピングもここで役立ちます。
最初に、load_Word2vec_format()
を使用してWord2vec.c形式のベクトルをロードします。次に、model.init_sims(replace=True)
を使用して、ユニット正規化を強制的にインプレースで破壊します(正規化されていないベクトルを破壊します)。
次に、モデルを新しいファイル名プレフィックスに保存します:model.save( 'GoogleNews-vectors-gensim-normed.bin'`。(これにより、モデルを作成するために一緒に保持する必要がある複数のファイルが実際にディスク上に作成されます再ロードされます。)
ここで、短いPython両方のメモリマップがベクトルをロードするプログラム、and配列全体をメモリに強制するプログラムを作成します。このプログラムも必要です。外部で終了するまで(マッピングを維持するまで)ハングするには、andすでにノルム化されたベクトルを再計算しないように注意してください。これは、ロードされたKeyedVectorsがベクトルが(通常、生のベクトルのみが保存され、必要に応じて標準バージョンが再計算されます。)
おおよそ次のように動作するはずです:
_from gensim.models import KeyedVectors
from threading import Semaphore
model = KeyedVectors.load('GoogleNews-vectors-gensim-normed.bin', mmap='r')
model.syn0norm = model.syn0 # prevent recalc of normed vectors
model.most_similar('stuff') # any Word will do: just to page all in
Semaphore(0).acquire() # just hang until process killed
_
これにはまだ時間がかかりますが、Webリクエストの前/外部で一度だけ実行する必要があります。プロセスが動作している間、ベクトルはメモリにマップされたままになります。さらに、他の仮想メモリのプレッシャーがない限り/まで、ベクトルはメモリにロードされたままになります。それは次のことにとって重要です。
最後に、Webリクエスト処理コードで、次の操作を実行できるようになりました。
_model = KeyedVectors.load('GoogleNews-vectors-gensim-normed.bin', mmap='r')
model.syn0norm = model.syn0 # prevent recalc of normed vectors
# … plus whatever else you wanted to do with the model
_
複数のプロセスが、読み取り専用のメモリマップファイルを共有できます。 (つまり、OSがファイルXが特定の位置にあるRAMにあることを認識すると、Xの読み取り専用マップバージョンも必要とする他のすべてのプロセスは、その再利用を指示されますその位置でのデータ。)。
したがって、このweb-reqeust load()
、および以降のアクセスは、前のプロセスがすでにアドレス空間とアクティブメモリに持ってきたデータをすべて再利用できます。すべてのベクトルに対する類似度計算を必要とする操作は、依然として複数のGBのRAMにアクセスして計算/ソートを行いますが、余分なディスクIOと冗長な再正規化は必要ありません。
システムが他のメモリ負荷に直面している場合、配列の範囲は、次の読み取りページに戻るまでメモリから落ちる可能性があります。また、マシンにRAMすべてのスキャンでページングインとアウトの混合が必要になり、パフォーマンスはどのようなものであってもイライラするほど悪くなります(そのような場合:get more RAMまたはより小さいベクトルで動作しますセット。)
ただし、十分なRAMがある場合は、マシンの共有ファイルマップメモリ機能が使用されるため、追加のWebサービスインターフェイスなしで、非常に高速な方法で元の/自然なロードおよび使用の直接コードを「動作させる」ことができます。サービスインターフェイスとして。
私はvzhongの埋め込みライブラリが大好きです。 https://github.com/vzhong/embeddings
WorditeのベクトルをSQLiteに保存します。つまり、モデルをロードする必要はなく、DBから対応するベクトルを取得するだけです:D
Googleニュースデータセットを使用するたびに、この問題が発生します。問題は、データセットに必要以上に多くの単語があることです。大量のタイプミスとそうでないものがあります。私がやっていることは、作業中のデータをスキャンし、最も一般的な5万語などの辞書を作成し、Gensimでベクターを取得し、辞書を保存することです。この辞書の読み込みには、2分ではなく0.5秒かかります。
特定のデータセットがない場合は、WMTの news dataset など、大きなデータセットの最も一般的な50または100kの単語を使用して開始できます。
他のオプションは、Gensimを常に実行し続けることです。 Gensimを実行するスクリプトの場合、 FIFOを作成 スクリプトは「サーバー」のように機能し、「クライアント」が書き込むファイルを読み取って、ベクトル要求を監視します。
最もエレガントなソリューションは、Word埋め込みを提供するWebサービスを実行することだと思います。例として Word2vec API を確認してください。インストール後、「レストラン」の埋め込みは次のように簡単です。
curl http://127.0.0.1:5000/Word2vec/model?word=restaurant
成功方法:
モデル= Word2Vec.load_Word2vec_format( 'wikipedia-pubmed-and-PMC-w2v.bin'、binary = True)model.init_sims(replace = True)model.save( 'bio_Word')
Word2Vec.load( 'bio_Word'、mmap = 'r')