はじめに
本質は指数関数 の計算で python の exp 関数を使う際の注意事項ですが、exp は sigmoid を算出するのによく使うので、そちらの例で紹介します。
sigmoid関数
よく活性化関数として使われます。
値を 0 か 1 に寄せたいけど、やりすぎて 0 と 1 の2値だけに潰されるのは嫌。そんな時に使い勝手の良い関数です。
![]() |
sigmoid の計算に良く使われる は爆発的に大きくなる関数です。
![]() |
---|
![]() |
定義域の x:709〜710 あたりで double でも扱いきれず、特別な値 Infinity (無限大)になります。更にその Infinity の数値を元に sigmoid を計算すると NaN(Not a Number) になる事があります。
実験
import numpy, sys, warnings
warnings.filterwarnings('ignore')
def sigmoid1(x):
return 1.0 / (1.0 + numpy.exp(-x))
def sigmoid2(x):
return numpy.exp(x) / (numpy.exp(x) + 1.0)
for x in [sys.float_info.max, 710, 709, sys.float_info.min, 0, -sys.float_info.min, -709, -710, -sys.float_info.max]:
print("|", x, "|", numpy.exp(-x), "|", numpy.exp(x), "|", sigmoid1(x), "|", sigmoid2(x), "|")
この表をみると を使えば良い、といった結論になりそうですが、そうは問屋が卸しません。
numpy の exp
上記のスクリプトでは warnings.filterwarnings('ignore') で誤魔化していますが、exp が inf を出す時と、その inf で sigmoid を計算する時に警告が出ます。
% cat sigmoid_test.py
import numpy
def sigmoid(x):
return 1.0 / (numpy.exp(-x) + 1.0)
print (numpy.exp(710))
print(sigmoid(-710))
%
% python sigmoid_test.py
sigmoid_test.py:7: RuntimeWarning: overflow encountered in exp
print (numpy.exp(710))
inf
sigmoid_test.py:3: RuntimeWarning: overflow encountered in exp
return 1.0 / (numpy.exp(-x) + 1.0)
0.0
ただ、警告は出ますが python の処理は続きます。
math の exp
python 標準パッケージ math の exp だと更に深刻で、Warning でなく Error でプログラムが止まります。
% cat sigmoid_math.py
import math
print(math.exp(710))
%
% python sigmoid_math.py
Traceback (most recent call last):
File "sigmoid_test.py", line 3, in <module>
print(math.exp(710))
OverflowError: math range error
対処案
は x:-710 あたりから inf に、
は x:710 あたりから inf になるので、x の正負で
と
を使い分けると良いでしょう。
% cat sigmoid_test2.py
import numpy
def sigmoid(x):
if x >= 0:
return 1.0 / (1.0 + numpy.exp(-x))
e = numpy.exp(x)
return e / (e + 1.0)
print(sigmoid(710))
print(sigmoid(-710))
%
% python sigmoid_test2.py
1.0
4.47628622567513e-309
最後に
計算精度的にどうなのとか気になるので、時間があったら突き詰めたいです。
あと、自分は tanh で計算する派でした。(┐「ε:)