4
2

More than 1 year has passed since last update.

シグモイド関数のオーバーフロー対策

Last updated at Posted at 2023-04-24

指数関数のオーバーフロー対策

最近見た実装で賢いなぁと思った実装があったのでご紹介します。

それが,タイトルにもある通りシグモイド関数のオーバーフロー対策です。

pythonは割と数値型(int, float,...)に関しては優秀で,あまり意識せずとも大きな数値を取ることが可能です。
しかし,流石に限度があるようで。
指数関数ぐらい発散速度が大きいものは簡単にオーバーフローします。

例)

>>> import numpy as np
>>> np.exp(100) #100くらいなら平気
2.6881171418161356e+43 #ただしかなり大きい桁数
>>> np.exp(709)
8.218407461554972e+307
>>> np.exp(710)
<stdin>:1: RuntimeWarning: overflow encountered in exp
inf
>>> np.exp(-1000)
0.0 #マイナス方向なら大丈夫

というわけで,$e^{710}$ という数値になるとオーバーフローしました。

肩の数字がマイナス方向に大きければ問題ないのですが,そうでなければ気をつけなければなりません。
これが効いてくるのが,シグモイド関数の実装時です。

シグモイド関数とは

$$
f(x) = \frac{1}{1+e^{-x}}
$$
で表される関数で,ロジスティック回帰とかニューラルネットワークの活性化関数とかでよく見られるやつです。

これ,一応定義域が実数全体をとるのですが,xがマイナス方向に大きい場合はどうなるでしょうか。

例えば,

$$
f(-1000) = \frac{1}{1+e^{-(-1000)}} = \frac{1}{1+e^{1000}}
$$

なので,$e^{1000}$がオーバーフローすることを考えると計算できないことになります。

そこで,実装上この関数を次のように場合分けをします。

f(x) = \left\{
\begin{array}{ll}
\frac{1}{1+e^{-x}} & (x \geq 0) \\
\frac{e^x}{1+e^{x}} & (x \lt 0) 
\end{array}
\right.

このようにすると,$x\geq0$の時は$e^{-x}$を計算して,$x\lt0$の場合は$e^x$を計算してくれるため,指数関数の肩の数字がマイナスの値になります。

よって,オーバーフロー対策になるわけです。

なお、if文で書いてもいいですが次のようにやると一行で書けます。

import numpy as np
def sigmoid(x):
    return np.exp(np.minimum(x, 0)) / (1 + np.exp(- np.abs(x)))
4
2
3

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
4
2