LoginSignup
10
7

More than 5 years have passed since last update.

Pythonでのsigmoid関数の高速な実装

Posted at

概要

機械学習アルゴリズムで頻繁に利用されるsigmoid関数だが、Pythonで実現しようとすると複数の方法が存在します。そこで、いくつかの実装の中でどれが一番速いのかを調べてみました。

方法

思いついた以下の方法について、sigmoidかけた値を算出して比較します。ただし、4と5に関しては使えるシーンが限定されている方法です。

  1. scipy.special.expitを呼ぶ (シンプルで良く使われている印象)
  2. 定義 $\frac{1}{1 + exp(-x)}$ 通り計算
  3. tanhを使って $0.5 \cdot \tanh(0.5 \cdot x) + 0.5$ で計算
  4. 与えられる値のrangeが決まっている場合、事前に計算しておき配列で保存
  5. 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.

結果

image.png

scipy.special.expitが他の方法と比較して2.5倍以上遅いことが分かりました。制約なしの中では定義通りに計算するのが速く、rangeの範囲の問題はある可能性はありますが、4は性能改善が誤差程度で、当然ですが5は高速ですが0付近で異なる値を返すという欠点がありました。

あとがたり

exp(-x)を計算する部分がボトルネックなので、ここを解消するためにフーリエ変換を用いて多項式に分解する方法とかもあるんですが、結局精度がいまいちでず、汎用的な近似にはなりませんでした…残念 :cry:

10
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7