16
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

python で sigmoid を算出する時は定義域に注意

Last updated at Posted at 2019-04-01

はじめに

本質は指数関数 e^x.png の計算で python の exp 関数を使う際の注意事項ですが、exp は sigmoid を算出するのによく使うので、そちらの例で紹介します。

sigmoid関数

よく活性化関数として使われます。
値を 0 か 1 に寄せたいけど、やりすぎて 0 と 1 の2値だけに潰されるのは嫌。そんな時に使い勝手の良い関数です。

55271264-2ef44d00-52ed-11e9-8675-a49be1fb4cee.png

sigmoid の計算に良く使われる e^x.png は爆発的に大きくなる関数です。

e^x.png
スクリーンショット 2019-04-02 1.31.20.png

定義域の x:709〜710 あたりで double でも扱いきれず、特別な値 Infinity (無限大)になります。更にその Infinity の数値を元に sigmoid を計算すると NaN(Not a Number) になる事があります。

実験

e^x.png は exp 関数で計算できます。

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), "|")
x.png e^-x.png e^x.png 1/(1+e^-x).png e^x/(e^x+1).png
1.7976931348623157e+308 0.0 inf 1.0 nan
710 4.47628622567513e-309 inf 1.0 nan
709 1.216780750623423e-308 8.218407461554972e+307 1.0 1.0
2.2250738585072014e-308 1.0 1.0 0.5 0.5
0 1.0 1.0 0.5 0.5
-2.2250738585072014e-308 1.0 1.0 0.5 0.5
-709 8.218407461554972e+307 1.216780750623423e-308 1.216780750623423e-308 1.216780750623423e-308
-710 inf 4.47628622567513e-309 0.0 4.47628622567513e-309
-1.7976931348623157e+308 inf 0.0 0.0 0.0

この表をみると 1/(1+e^-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

対処案

e^-x.png は x:-710 あたりから inf に、e^x.png は x:710 あたりから inf になるので、x の正負で 1/(1+e^-x).pnge^x/(e^x+1).png を使い分けると良いでしょう。

% 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 で計算する派でした。(┐「ε:)

16
6
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
16
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?