word2vecに関してのもっと詳しい話。
Skip-gram
Skip-gramについてもうちょっと詳しく。入力ベクトルを元に出力ベクトルを決めるのは、Softmax関数を使うんだけど、この分母の計算が素直にやると語彙オーダーで重たい。階層的SoftmaxとNagetive Samplingの2つの方法が紹介されている。
階層的Softmaxだと語彙の対数オーダーに減る。これは最初に単語をハフマン符号にしておいて、符号の各位置のビットを見て一致するかどうかを教師データにしてビットの数だけ学習を繰り返す手法。ビットはword2vecの実装では40個になってる。各単語ごとに40回学習するのは効率が悪いと感じるけど、各単語ごとに出力層の各単語(数万個!)の出力を計算することに比べればはるかに安い。
Negative Samplingはざっくり言うと適当に選んだk個を「正しくない回答」として逆向きの学習をさせるって方法。小さいデータセットでkは5–20個、大きいデータセットなら2-5個でよいとのこと。word2vecの実装では--negativeでkを設定する。デフォルトでは階層的Softmaxを使うようになっていてNegative Samplingは使われない。もっぱら高速化のためのテクニックだから、必要がなかったら使わなくていいかも。ちなみに僕の蔵書100冊分のデータ(96MB)で学習に3分半、中谷さんにもらった日本語Twitterのデータ(1GB)で40分だった。
Subsampling of Frequent Words
出現頻度の高い単語を間引きましょうって話。よくtheだとかをstop wordとか呼んで、最初から学習データから取り除いてしまう処置が行われているけども、それを頻度を使って滑らかにやろうとしている。
式(5)のsqrt(threshold / freq(word))ってのはどういうことかって言うと、まず頻度freq(word)がthresholdより小さい場合にはsqrtの中身が1を超えて、間引く確率が負になる。つまり間引かない。
ところでword2vecの該当部の実装はこれなんだけど、論文の数式と違ってthreshold / freq(word)の項が残ってしまう気がするんだ気のせいだろうか。そして残ったとしても上記振る舞いには全く影響がない…sqrtいらんのとちゃうん…。
if (sample > 0) { real ran = (sqrt(vocab[word].cn / (sample * train_words)) + 1) * (sample * train_words) / vocab[word].cn; next_random = next_random * (unsigned long long)25214903917 + 11; if (ran < (next_random & 0xFFFF) / (real)65536) continue; }## Learning Phrases
複数単語からなる節も学習したいよねという話。既存の色々な節抽出アルゴリズムがあるけどここではunigramとbigramと、適当に決めた割引係数と閾値でくっつけたら良さげなものをくっつけるという作業を何パスかやりました、とのこと。割引系数や閾値をどう変えるとどうなるかは書かれてなくて、たぶんパラメータを変えながら何度も実験して、良い値になったものを出してるんだろうな。
出典
さいごに
この記事はDeep Learningに興味を持った著者が、関連論文を読んで勉強しながら書いているものです。そのため間違いなどが含まれている可能性があります。もしなにか気になる点がありましたらご指摘いただけるとありがたいです。