概要
機械学習アルゴリズムで頻繁に利用されるsigmoid関数だが、Pythonで実現しようとすると複数の方法が存在します。そこで、いくつかの実装の中でどれが一番速いのかを調べてみました。
方法
思いついた以下の方法について、sigmoidかけた値を算出して比較します。ただし、4と5に関しては使えるシーンが限定されている方法です。
-
scipy.special.expit
を呼ぶ (シンプルで良く使われている印象) - 定義 $\frac{1}{1 + exp(-x)}$ 通り計算
- tanhを使って $0.5 \cdot \tanh(0.5 \cdot x) + 0.5$ で計算
- 与えられる値のrangeが決まっている場合、事前に計算しておき配列で保存
- 0付近の値が与えられない場合、$\frac{x}{1 + |x|}$ で算出
実装
import numpy as np
from scipy.special import expit # 1.
# 2.
normal_expit = lambda x: 1 / (1 + np.exp(-x))
# 3.
tanh_expit = lambda x: 0.5 * np.tanh(0.5 * x) + 0.5
# 4.
min_range, max_range = (-5, 5)
exponent = 6
pre_computed = expit(np.arange(min_range, max_range, 10 ** - exponent))
def computed_expit(x, min_range, pre_computed):
return pre_computed[np.floor((x - min_range) * (10 ** exponent)).astype(int)]
abs_expit = lambda x: x / (1 + np.abs(x)) # 5.
結果
scipy.special.expit
が他の方法と比較して2.5倍以上遅いことが分かりました。制約なしの中では定義通りに計算するのが速く、rangeの範囲の問題はある可能性はありますが、4は性能改善が誤差程度で、当然ですが5は高速ですが0付近で異なる値を返すという欠点がありました。
あとがたり
exp(-x)
を計算する部分がボトルネックなので、ここを解消するためにフーリエ変換を用いて多項式に分解する方法とかもあるんですが、結局精度がいまいちでず、汎用的な近似にはなりませんでした…残念