-Deep Learning- 出力層の活性化関数

ニューラルネットワークは,分類問題,回帰問題の両方に用いることが可能です.ただし,分類問題なのか,回帰問題なのかで,出力層の活性化関数を変更する必要があります.
一般的に,回帰問題では恒等関数を,分類問題ではソフトマックス関数を用います(入ってきた入力信号をそのまま出力する恒等関数については,前回の投稿を参照のこと).

分類問題で使われるソフトマックス関数は

 

という式で表されます.式が表しているように,ソフトマックスの出力は,全ての入力信号から影響を受けて決まることになります.
Pythonインタプリタを使って実装例を示します.

>>> import numpy as np
>>> a = np.array([0.3, 2.9, 4.0])
>>> 
>>> exp_a = np.exp(a)   # Exponential
>>> print(exp_a)
[ 1.34985881 18.17414537 54.59815003]
>>> 
>>> sum_exp_a = np.sum(exp_a)   # Sum of exponential
>>> print(sum_exp_a)
74.1221542101633
>>> 
>>> y = exp_a / sum_exp_a
>>> print(y)
[0.01821127 0.24519181 0.73659691]
>>> 

上記の実装は,ソフトマックス関数を正しく表現できていますが,コンピュータで計算を行う際には,欠陥があります.その欠陥は,オバーフロー(大きな値同士の割り算によって数値が不安定になる)対策ができていないことです.

オーバーフローが生じる例を以下に示します.
>>> import numpy as np
>>> a = np.array([1010, 1000, 990])
>>> np.exp(a) / np.sum(np.exp(a))       #Softmax function
__main__:1: RuntimeWarning: invalid value encountered in true_divide
array([nan, nan, nan])
>>> 
普通に計算すると nan (not a number) 

ソフトマックス関数の実装の改善案は下式のようになります.

f:id:HidehikoMURAO:20181231225350p:plain

 
C'にはどのような値を用いても良いのですが,オーバーフロー対策としては,入力信号の中で最大の値を用いることが一般的です.
この方法を実装してみます.
>>> c = np.max(a)       # 1010
>>> a - c
array([  0, -10, -20])
>>> 
>>> np.exp(a - c) / np.sum(np.exp(a - c))
array([9.99954600e-01, 4.53978686e-05, 2.06106005e-09])
>>> 
普通に計算した場合は nan であった場合でも計算できています.
 
最初の計算でも同じ結果が出るのかを確認してみます.
>>> def softmax(a): 
...     c = np.max(a)
...     exp_a = np.exp(a - c)   # Overflow countermeasure
...     sum_exp_a = np.sum(exp_a)
...     y = exp_a / sum_exp_a
...     return y
... 
>>> a = np.array([0.3, 2.9, 4.0])
>>> y = softmax(a)
>>> print(y)
[0.01821127 0.24519181 0.73659691]
>>> np.sum(y)
1.0
>>> 
 
ソフトマックス関数の出力は,0.0から1.0の間の実数になります.また,ソフトマックス関数の出力の総和は1.0になります.この総和が1.0になるという性質は,ソフトマックス関数の重要な性質です.この性質を使うことで,ソフトマックス関数の出力を確率として解釈が可能になります.
また,もう一つの注意点としては,ソフトマックス関数を適用しても各要素の大小関係は変わりません.これは,指数関数(y = exp(x))が単調増加する関数であることに起因します.
 
ニューラルネットワークのクラス分類では,出力の一番大きいニューロンに相当するクラスだけを認識結果とします.そして,ソフトマックス関数を適用しても出力の一番大きいニューロンの場所は変わりません.そのため,ニューラルネットワークが分類を行う際には,出力層のソフトマックス関数を省略することが可能です.