この記事では、勾配消失へ対処することを主軸に、活性化関数についてまとめます。
活性化関数とは
活性化関数とは、層の出力と次の層の入力をつなぐ非線形な関数です。
これがあることにより、サポートベクトルマシンのように直線を引いて分類するのではなく、くねくねとした線で分類できるようになります。
最後の層では、活性化関数の出力がそのままモデルの出力になります。
代表的な活性化関数として、以下のものが挙げられます。
- シグモイド関数
- tanh関数
- reLU関数(ランプ関数)
活性化関数早見表
シグモイド関数
\begin{aligned}
f(x) &= \frac{1}{1+e^{-x}} \\[10px]
f'(x) &= (1 - f(x))f(x)
\end{aligned}
tanh関数
\begin{aligned}
f(x) &= \frac{e^x - e^{-x}}{e^x + e^{-x}} \\[10px]
f'(x) &= 1-f^2(x)
\end{aligned}
reLU関数(ランプ関数)
\begin{aligned}
f(x) &= \begin{cases}
x & (x > 0) \\
0 & (x \le 0)
\end{cases} \\[10px]
f'(x) &= \begin{cases}
1 & (x > 0) \\
0 & (x \le 0)
\end{cases}
\end{aligned}
シグモイド関数
まず、ニューラルネットワークのもとになったニューロンについて考えてみます。
ニューロンは、電気信号の強さが一定以上になると、急激に出力が跳ね上がる性質があります。いわゆる「発火」です。
シグモイド関数は、この、ニューロンの性質を見事に表現できる関数です。
以下がシグモイド関数のグラフです。
グラフを見ると分かるのですが、シグモイド関数は、x=0.0を中心にして急激に値が増加します。
これによって、2,3層くらいのNNではうまく予測することができたのですが、4層5層と層を深くしていったときに、急激に予測精度が下がってしまいました。
何が起きたのでしょうか。
次に、以下のグラフを見てください。
このグラフの下側にある山のような線は、シグモイド関数を微分したものです。
x=0.0で最大値0.25となっており、それ以外では、0に近い非常に小さな値となっています。
NNでは予測の誤差が逆伝搬されていきますが、このとき、層ごとに活性化関数の微分値が掛け合わされます。
シグモイド関数は0.0~0.25の小さな微分値を返すため、層をまたぐたびに伝播する誤差が小さくなっていき、そのうち消失してしまいます。
そのため、シグモイド関数では、深い層の学習をすることができませんでした。
場合によってはできることがあるかもしれませんが、多くの場合で失敗するので実用性に欠けます。
なお、シグモイド関数は0~1を出力する性質から確率と相性が良く、出力層の活性化関数として今でもよく用いられています。
tanh関数
次に候補として挙げられたのが、tanh関数です。
以下はtanh関数のグラフです。
tanh関数は、シグモイド関数とちがい、-1から1へ跳ね上がる関数です。
tanh関数の微分はどのように変化するのでしょうか?
tanh関数の微分値は、0~1の範囲で変化します。したがって、シグモイド関数と比較して勾配消失が起こりにくいです。
比較すると分かりやすいです。
tanh関数の登場により勾配消失問題は改善されましたが、tanh関数は多くの値で勾配を小さくしてしまうため、10層を超えるような深さでは学習することができませんでした。
なお、tanh関数は、出力が-1~1という性質や、0を中心に勾配が伝わる性質により、特定分野で現在も用いられています。
reLU関数
次に登場したのが、現在の標準に位置する、reLU関数です。ランプ関数とも呼ばれます。
reLU関数は以下のようなグラフになります。
非常に単純な関数ですが、この関数の良さは微分値を見れば分かります。
見ての通り、xが正の部分では、微分値が1になっています。したがって、多くの場合で勾配を減らさずに伝えることができます。
reLU関数の登場によって、勾配消失問題が大きく改善され、深い層をもつNNの学習ができるようになりました。
Leaky reLU関数
ここで、reLU関数のグラフのうち、xが負の部分を見てください。
微分値が0になっています。ここが原因で、やはり勾配消失は起きてしまうのですが、ここを傾けて微分値を0にならないようにしてしまえば良さそうだと思いませんか?
そうして生まれたのがLeaky reLU関数です。
以下は、Leaky reLU関数とその微分のグラフです。
xが負の部分で少しの傾きを持たせ、どんな値でもある程度の勾配が伝わるようにしました。
これによって勾配消失問題が大きく改善される...と期待されていたのですが、思ったほど改善はしないどころか、場合によってはreLU関数を下回る性能でした。とはいえ、場合によってはreLU関数よりも良い性能を示すため、現役ではあります。







