鴨川η

not δ

sigmoid table for word2vec&fasttext

はじめに

Skip-gram&NegativeSamplingでは(正例数 (neg+1) 反復回数)だけ出力層でsigmoid関数を呼ぶ。 これを避けるためにword2vecやfasttextではsigmoid関数の評価値をキャッシュすることで高速化している。 ざっくりとした解説を以下に書く。

本題

word2vecの拡張ライブラリであるfasttextの変数と実装に従って説明する。

まず、関係する定数として SIGMOID_TABLE_SIZEMAX_SIGMOID がある。

SIGMOID_TABLE_SIZEは、事前に計算するsigmoid関数の回数。この値は小さいほど荒い計算値を使うことになる。 word2vecでは1000、fasttextでは512

MAX_SIGMOIDは、sigmoid関数の引数の最大値。 この値より大きければ1を返す(-MAX_SIGMOIDより小さければ0)。 word2vecでは6、fasttextでは8

Pythonで書くと以下のようになる。

import numpy as np

SIGMOID_TABLE_SIZE = 512
MAX_SIGMOID = 8

t_sigmoid = np.zeros(SIGMOID_TABLE_SIZE)

for i in range(SIGMOID_TABLE_SIZE):
    x = (i / SIGMOID_TABLE_SIZE * 2 - 1) * MAX_SIGMOID
    t_sigmoid[i] = 1 / (np.exp(-x)+1.)


def sigmoid(x):
    if x >= MAX_SIGMOID:
        return 1.
    elif x <= -MAX_SIGMOID:
        return 0.
    else:
        return t_sigmoid[(int)((x + MAX_SIGMOID) * (SIGMOID_TABLE_SIZE / MAX_SIGMOID / 2))]

sigmoid(x=0.)  # 0.5
sigmoid(x=0.7) # 0.66541055874681398
sigmoid(x=10.) # 1.0

(i / SIGMOID_TABLE_SIZE * 2 - 1) * MAX_SIGMOIDは、indexi-MAX_SIGMOIDからMAX_SIGMOIDSIGMOID_TABLE_SIZE-1に等分割したときのi番目の実数値に変換している。 当然だが、sigmoid(x)の最終行は、これの逆変換になっている。

その他

の高速計算はexp(x)の高速計算 ~理論編~を読んで理解したいと思いました。