指数関数を含む関数のオーバーフローと、その対策

プログラミング
Sponsored

概要

この記事では、分子分母に指数関数を含む活性化関数におけるオーバーフローの問題と、その解決策について説明する。

本稿で取り扱うのは

  • ソフトマックス関数
  • シグモイド関数
  • tanh関数
  • ソフトプラス関数

である。

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

指数関数 \(y=\exp(x)\) のグラフを書くと、以下のようになる。

図1

すなわち、 \(x\) の値が正の方向に少しでも大きくなると、 \(\exp(x)\) はかなり大きくなることがわかる。

コンピュータで扱える数値の大きさには限界があり、指数関数はすぐに上限を越えてオーバーフローする。具体的には、64ビット浮動小数点数で表せる最大値は1.7976931348623157e+308なので

$$\ln(1.7976931348623157\times 10^{308})=709.7\cdots$$

より、 \(\exp(710)\) を表すことができない。

(参考)

Numpyで浮動小数点数の精度・最大値・最小値を取得
概要 この記事では、Numpyで扱える浮動小数点数の精度や最大・最小値の範囲を取得する方法について説明する。 また、おまけとして、整数型の最大・最小値を取得する方法についても述べる。 numpy.finfo() 関数の概要 Numpyで扱え...

逆に、 \(x\) が負の時は、絶対値が大きく変化しても \(\exp(x)\) の値はほとんど変化しないことがわかる(図1)。

したがって、指数関数を含む関数は、変形して指数関数の内部を負にしてやることで計算途中のオーバーフローを回避することができる。

具体例

ソフトマックス関数

性質

ソフトマックス関数は、カテゴリ分類の機械学習の活性化関数等として使われ、以下のように定義される。

$$S_k(\mathbf{x})=\frac{\exp(x_k)}{\sum_i\exp(x_i)}$$

ここで \(S_k\) は \(\mathbf{x}=\{x_1,\ldots,x_n\}\) というベクトルの関数であり、 \((0, 1)\) の値をとる。

これは、指数関数単体は非常に大きな値を取りうるが、その場合は分子・分母がともに大きくなり、割り算の結果、常識的な範囲に収まるためである。したがって、計算機でそれぞれの指数関数を個別に計算してから分子÷分母を求めようとすると、途中でオーバーフローを起こし計算が停止する。

対策

\(\mathbf{x}\) の要素の最大値を \(x_M\) とする。ソフトマックス関数は以下の形に変形できる。

$$S_k(\mathbf{x})=\frac{\exp(x_k-x_M)}{\sum_i\exp(x_i-x_M)}$$

この結果、指数関数のうち最も大きいものでも \(\exp(0)=1\) となり、オーバーフローを防ぐことができる。

証明

ソフトマックス関数の分子分母に、同じ数 \(C\neq 0\) を掛けても値は変わらない。すなわち

$$S_k(\mathbf{x})=\frac{C\exp(x_k)}{C\sum_i\exp(x_i)}$$

$$=\frac{\exp\{\ln(C)\}\exp(x_k)}{\exp\{\ln(C)\}\sum_i\exp(x_i)}$$

$$=\frac{\exp(x_k+\ln(C))}{\sum_i\exp(x_i+\ln(C))}$$

となる。

ここで、 \(C'=-\ln(C)\) とおくと

$$S_k(\mathbf{x})=\frac{\exp(x_k-C')}{\sum_i\exp(x_i-C')}$$

であり、すなわち、各指数関数の内部から、同じ数 \(C'\) を引いてもソフトマックス関数の値は変化しない。

シグモイド関数

シグモイド関数も機械学習の活性化関数として使われ、以下のように定義される。

$$S(x)=\frac{1}{1+\exp(-x)}$$

この式は、ソフトマックス関数で \(\mathbf{x}=\{0, -x\}\) とした場合に等しい( \(\frac{\exp(0)}{\exp(0)+\exp(-x)}\) )ため、 \(0, -x\) のうち、大きい方を各指数関数から引けばオーバーフローを防ぐことができる。

つまり

$$S(x)=\frac{\exp\{-\max(0, -x)\}}{\exp\{-\max(0, -x)\}+\exp\{-x-\max(0, -x)\}}$$

$$=\frac{\exp\{\max(0, x)\}}{\exp\{\max(0, x)\}+\exp\{\max(-x, 0)\}}$$

またはこれを場合分けを用いて表記し

$$S(x)=\begin{cases}\frac{1}{1+\exp(-x)}&&(x\geq 0)\\ \frac{\exp(x)}{\exp(x)+1}&&(x< 0)\end{cases}$$

として数値計算する。

tanh関数

LSTMなどのリカレントな機械学習モデルの活性化関数として使われることが多いtanh関数は、値域が \((-1,1)\) となる関数として以下のように定義される。

$$\tanh(x)=\frac{\exp(x)-\exp(-x)}{\exp(x)+\exp(-x)}$$

この式においても、最大値をとる指数関数が \(\exp(0)=1\) となるように定数を引けばよい。

場合分けを用いて表現すると

\(x\geq 0\) のとき

$$\tanh(x)=\frac{\exp(x-x)-\exp(-x-x)}{\exp(x-x)+\exp(-x-x)}$$

$$=\frac{1-\exp(-2x)}{1+\exp(-2x)}$$

\(x\geq 0\) のとき

$$\tanh(x)=\frac{\exp(x+x)-\exp(-x+x)}{\exp(x+x)+\exp(-x+x)}$$

$$=\frac{\exp(2x)-1}{\exp(2x)+1}$$

すなわち

$$\tanh(x)=\begin{cases}\frac{1-\exp(-2x)}{1+\exp(-2x)}&&(x\geq 0)\\ \frac{\exp(2x)-1}{\exp(2x)+1}&&(x< 0)\end{cases}$$

と表せる。または、定義式を先に

$$\tanh(x)=\frac{\exp(x)+\exp(-x)-2\exp(-x)}{\exp(x)+\exp(-x)}$$

$$=1-\frac{2\exp(-x)}{\exp(x)+\exp(-x)}$$

$$=\frac{2\exp(x)}{\exp(x)+\exp(-x)}-1$$

等と変形した上で同様の場合分けを行い、

$$\tanh(x)=\begin{cases}\frac{2}{1+\exp(-2x)}-1&&(x\geq 0)\\ 1-\frac{2}{\exp(2x)+1}&&(x< 0)\end{cases}$$

と計算しても、同様にオーバーフローを防ぐことができる。

ソフトプラス関数

ソフトプラス関数ReLUに似た活性化関数であり、

$$S(x)=\ln\{1+\exp(x)\}$$

と定義される。値域は \((0, \infty)\) である。

\(x>>0\) の時に指数関数の計算でオーバーフローが起こりうるため、

$$S(x)=\ln[\exp(x)\{\exp(-x)+1\}]$$

$$=\ln\{\exp(x)\}+\ln\{\exp(-x)+1\}$$

$$=x+\ln\{\exp(-x)+1\}$$

と変換する。場合分けを用いて表記すると

$$S(x)=\begin{cases}x+\ln\{\exp(-x)+1\}&&(x\geq 0)\\ \ln\{1+\exp(x)\}&&(x< 0)\end{cases}$$

となる。

Comments