gensimとword2vec

Pocket

何かと話題のword2vecですが、自分も使ってみようと思って試行錯誤したことを書いてみます。間違いなどあればぜひコメントください。

GoogleのC実装

https://code.google.com/p/word2vec/にある、C言語による実装は独立したアプリケーションで、Apache 2.0ライセンスで提供されています。

ビルドした状態でword2vecコマンドを使って学習、モデルを作成し、distance等のコマンドからモデルをもとにデータを出力します。以下はword2vecを引数なしで実行したときの実行例です。

./word2vec -train data.txt -output vec.txt -size 200 -window 5 \
 -sample 1e-4 -negative 5 -hs 0 -binary 0 -cbow 1 -iter 3

各オプションの意味は以下になります。

  • train: 学習対象のテキストデータ(コーパス)
  • size: 次元数(デフォルトは100)
  • window: skip-gramの対象とする単語の最大数を指定(多分)デフォルトは5
  • sample: 単語を無視する際の頻度の閾値(デフォルトは1e-3)
  • threads: 処理するスレッド数
  • hs: Hierarchical Softmax(階層的Softmax)を使う(1)/使わない(0)
  • negative: ネガティブサンプリングに用いる単語数
  • binary: 出力結果をバイナリ形式にする(1)/テキスト形式(0)
  • cbow: Continuous Bag-of-Words 連続単語集合モデルを使う(1)/使わない(0)
  • iter: 学習する回数(イテレーション)の指定。デフォルトは5

CBOWとSkip-gramについてはFiS Projectの記事がわかりやすいです。階層的SoftmaxとネガティブサンプリングについてはnishioさんによるQiitaの記事が詳しいです。

gensim(Python)実装

gensimはPythonとCを組み合わせて記述された、文書解析ソフトウェアパッケージです。ライセンスはLGPL3+で、ソースはhttps://github.com/piskvorky/gensimで公開されています。

もともと複数の計算モデルを扱えるようになっていたようなのですが、2013年9月ごろにword2vecが追加されたようです。webで紹介される実装はこちらの方が多いようです。

Google実装はサンプル実装という面が強く、コマンドからできることに限りがあります。それに比べるとgensimはできることが多い(任意の数の単語のpositive/negativeな演算ができる)のですが、モデル構築にメモリをより使用します。

1GBのテキストをコーパスとしてgensimのword2vecに与えたところ、メインメモリ8GBのマシンでスラッシングを起こしてしまいました。Google実装であれば、1GB程度のテキストはオンメモリで処理できるようです。また、POSIX threadによるマルチスレッド処理にも対応しています。

幸いなことに、gensimのWord2VecではGoogle実装のモデルを読み込ませることができます。大きなデータを扱う際には、これらを組み合わせるとよい感じです。

from gensim.models import word2vec
model = word2vec.Word2Vec.load_word2vec_format("model.bin", binary=True)

pythonで処理したモデルもファイルに保存することができます。

from gensim.models import word2vec

model = word2vec.Word2Vec.load_word2vec_format("model.bin", binary=True)
model.save("gensim-model.bin")
#model.load("gensim-model.bin")

gensimでは、trainメソッドで後から追加学習させることもできるのですが、既に構築したモデルに存在しない単語は扱えない(語彙が増やせない)ようです。これに気付かず、分割したテキストデータをちょっとづつ学習させるというようなことをやらせようとしてはまりました。

結局、大きなコーパスを取り扱う際にはC実装でモデルを構築して、それをgensimで読み込むという使い方をするのが良いようです。

その他参考にした資料

追記(2015/5/20)

gensimでword2vecの処理がシングルスレッドでしかできないような表現でしたが、Word2Vecの引数にworker=2等とすることでマルチコア動作することに気付きました。それでも処理速度はGoogle実装の方が早いとは思いますが、記録として残しておきます。