gensimのword2vecを使ってembeddingを計算するときに再現性が取れなくて悩んでいたんですが、こちらのツイートを拝見しました。
NotebookでgensimのWord2Vecの学習を再現するには、重みの初期化に使われるハッシュ関数を自作して再現するものに変えれば良いみたいです。#dsb2019反省会 pic.twitter.com/PGQcA8I94H
— yabea (@yabea18) 2020年2月29日
そんなこんなで試しにやってみたので記録として残しておきます。
コード
普通に書く
書いてあるものそのままなんで、やってみます。 まずは普通にやってみます。
普通にやると、毎回違うベクトルが計算されていることがわかります。
再現性を取るには
gensimのドキュメントでseedに関する記述を見ると、
seed (int, optional) – Seed for the random number generator. Initial vectors for each word are seeded with a hash of the concatenation of word + str(seed). Note that for a fully deterministically-reproducible run, you must also limit the model to a single worker thread (workers=1), to eliminate ordering jitter from OS thread scheduling. (In Python 3, reproducibility between interpreter launches also requires use of the PYTHONHASHSEED environment variable to control hash randomization).
google翻訳先生によれば
乱数ジェネレーターのシード。各単語の初期ベクトルは、単語+ str(seed)の連結のハッシュでシードされます。完全に決定論的に再現可能な実行のために、モデルを単一のワーカースレッド(workers = 1)に制限する必要があることに注意してください、OSスレッドスケジューリングから順序のジッターを排除します。(Python 3では、インタープリターの起動間の再現性にも、ハッシュランダム化を制御するPYTHONHASHSEED環境変数の使用が必要です)。
要するに、
- seedを統一すること
- workerを1にすること
- PYTHONHASHSEEDを統一すること
ってことです。
最初の実装で再現性がなんで取れないのかを確認してみると
class gensim.models.word2vec.Word2Vec(sentences=None, corpus_file=None, size=100, alpha=0.025, window=5, min_count=5, max_vocab_size=None, sample=0.001, seed=1, workers=3, min_alpha=0.0001, sg=0, hs=0, negative=5, ns_exponent=0.75, cbow_mean=1, hashfxn=<built-in function hash>, iter=5, null_word=0, trim_rule=None, sorted_vocab=1, batch_words=10000, compute_loss=False, callbacks=(), max_final_vocab=None)
となっており、workersが3になっていることが原因のようです。(seedは初期値に固定されており、同一環境でPYTHONHASHSEEDは同じのはずなので)
そのため、workersを1にしてあげて実装し直すと、再現性が取れることがわかります。
tweetで指摘されていたhashfxnですが、大本のドキュメントではこのように書かれています。
hashfxn (function, optional) – Hash function to use to randomly initialize weights, for increased training reproducibility.
これ、hash関数の定義なんですが、本当にhash関数を定義しているから再現性が取れているのか気になりました。 ハッシュ関数なんで、入力値が一緒なら出力は一意に決定されるはずで、事前定義されていてもその事実は変化しないように思います。 (実際上の実験でも指定なしで再現出来ていますし。)
一応、そういった状況ようにhash関数の指定方法だけ記録に残しておきます。
まとめ
gensimのw2vを使う際に、同じ環境でで再現性が取れないときは、
- seedを統一すること
- workerを1にすること
- PYTHONHASHSEEDを統一すること
を確認します。基本的には上の3つが担保されていないことが原因だと思われます。 別環境で実行する際など、上記を指定しても再現性が取れない場合などはhash関数を指定して環境に依存しないようにする必要があるということだと思います。
感想
こうやって再現性を取るんですね。知らなかった。。。 というわけで、備忘録です。