この記事を3行でまとめると
Word2Vecで膨大なデータをミニバッチ学習するために
gensimを使ってコードを書いて
ついでにどうでもいいプルリクを送りつけた話
1. 導入
gensimを使ってWord2Vecを学習するとき、普通は1つの学習データを食わせて学習するかと思います。
しかし、学習データのサイズが大きすぎるとメモリにのらないんじゃないかと不安になります。(数GBのデータが10個ほどあるような場合を想定しています。)
そこで、学習データを複数に分けて読み込み、別々に学習するために
gensimのソースコード読んで、目的に叶うコードを書きました。
2. 環境
Python 3.4.3
gensim (2.3.0)
3. 目的
複数のファイルを順次モデルに渡していき、その都度学習させること
4. コード
from gensim.models import word2vec
model = word2vec.Word2Vec(window=1, min_count=1)
files=["data0.txt", "data1.txt", "data2.txt", ...]
update=False
for file in files:
# 適当な処理"load"をして学習用のsentencesをfiles[i]から抜き出す
sentences = load(file)
model.build_vocab(sentences, update=update)
update=True
for file in files:
sentences = load(file)
model.train(sentences, total_examples=len(sentences),
epochs=model.iter)
# !!注意!! (追記:2018/1/12)
# あとで判明しましたが中の人によるとこのコードのようにtrain関数を複数回使うことは望ましくありません。
# コメントに書いたようにPathLineSentencesクラスを使うと
# train関数の使用は1回ですみ、訓練しつつ逐次的にデータを読み込むことが可能です。
# build_vocabも1回ですみます。
※
model.iterはdefaultでは5
これで目的達成です。
お疲れ様でした。
おまけ:重箱の隅
gensimでは単語の出現回数をbuild_vocabするたびに0から数えなおしています。
そのため、今回のように異なるデータを複数回に分けて扱う場合、厳密な意味でmin_count以下の出現回数の単語のみを弾くことは現状のソースコードではできません。
例えば、min_countを2に指定した(=頻度1の単語はカウントしない)場合
sentences1=[["a","a","x"], ["b","b","y"]]
でbuild_vocabした後に
sentences2=[["b","b","x"], ["a","a","y"]]
でbuild_vocabして学習すると、それぞれのbuild_vocabにおいて"x"と"y"はともに出現回数は1なので語彙としてカウントされません。
しかしsentences1とsentences2を合わせた全体での出現回数は"x"も"y"も2なのでmin_countの制約をクリアしており、語彙として加えられるべきです。
この問題()を解決するためには以下のようにソースコードを書き変えました。
・・・それなりに大きいサイズなのに、各データでmin_countを下回っているような単語は超どうでもいいものな気がするので、本当に重箱の隅だと思います・・・
が、せっかくコード追加したのでプルリク送ってみました。
もしかするとプロジェクトによってはmin_countが重要なファクターになることがあるかもしれません。
https://github.com/RaRe-Technologies/gensim/pull/1606
英語つらい