以下の式で表現される関数をソフトマックス関数といい、ディープラーニングの活性化関数の1つとして利用される。
\[
\begin{eqnarray}
f_i(x) = \displaystyle \frac{e^{x_i}}{ \displaystyle \sum_{k=1}^{n}e^{x_k} }
\end{eqnarray}
\]
\(n\)個のデータがあるときに、その合計を\(1\)(\(100\)%)になるように調整してくれるため、ソフトマックス関数は、多クラス分類を行うニューラルネットワークの出力層の活性化関数でよく利用される。
今回は、ソフトマックス関数とその微分を計算してみたので、その結果を共有する。
Numpyを利用して、ソフトマックス関数の値を計算した結果は、以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | import numpy as np # 引数のリストの最大値 def list_max(data_list): return np.max(data_list) # 底をネイピア数e(≒2.7)とする指数関数の値 def exp_list(data_list): return np.exp(data_list) # 底をネイピア数e(≒2.7)とする指数関数の値の合計 def exp_list_sum(data_list): return np.sum(exp_list(data_list)) # ソフトマックス関数の値 def softmax_list(data_list): after_data_list = data_list - np.max(data_list) return np.exp(after_data_list) / np.sum(np.exp(after_data_list)) # ソフトマックス関数の値の合計 def softmax_list_sum(data_list): return np.sum(softmax_list(data_list)) # 検証用データ data_list = np.array([0, 1, 2, 3]) print("*** 引数のリスト ***") print(data_list) print() print("*** 引数のリストの最大値 ***") print(list_max(data_list)) print() print("*** 底をネイピア数eとする指数関数の値 ***") print(exp_list(data_list)) print() print("*** 底をネイピア数eとする指数関数の値の合計 ***") print(exp_list_sum(data_list)) print() print("*** ソフトマックス関数の値 ***") print(softmax_list(data_list)) print() print("*** ソフトマックス関数の値の合計 ***") print(softmax_list_sum(data_list)) print() |
なお、上記「softmax_list」メソッドを呼び出す際、引数のリストの最大値を減算しているのは、以下のdata_list_2のようなオーバーフローを防ぐためとなる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import numpy as np # ソフトマックス関数の値(改良前) def softmax_list_before(data_list): return np.exp(data_list) / np.sum(np.exp(data_list)) # 検証用データ data_list_1 = np.array([0, 1, 2, 3]) data_list_2 = np.array([1000, 1001, 1002, 1003]) print("*** 引数のリスト data_list_1 ***") print(data_list_1) print() print("*** ソフトマックス関数の値(改良前) data_list_1 ***") print(softmax_list_before(data_list_1)) print() print("*** 引数のリスト data_list_2 ***") print(data_list_2) print() print("*** ソフトマックス関数の値(改良前) data_list_2 ***") print(softmax_list_before(data_list_2)) |
実際に、ソフトマックス関数を求める際に引数のリストの最大値を減算すると、data_list_2のオーバーフローが発生しないことが確認できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | import numpy as np # ソフトマックス関数の値(改良後) def softmax_list_after(data_list): after_data_list = data_list - np.max(data_list) return np.exp(after_data_list) / np.sum(np.exp(after_data_list)) # 検証用データ data_list_1 = np.array([0, 1, 2, 3]) data_list_2 = np.array([1000, 1001, 1002, 1003]) print("*** 引数のリスト data_list_1 ***") print(data_list_1) print() print("*** ソフトマックス関数の値(改良後) data_list_1 ***") print(softmax_list_after(data_list_1)) print() print("*** 引数のリスト data_list_2 ***") print(data_list_2) print() print("*** ソフトマックス関数の値(改良後) data_list_2 ***") print(softmax_list_after(data_list_2)) |
また、\( f_i(x) = \displaystyle \frac{e^{x_i}}{ \displaystyle \sum_{k=1}^{n}e^{x_k} } \) を\(x\)について偏微分すると、以下のようになる。
\[
\begin{eqnarray}
\displaystyle \frac{\partial}{\partial x_i} \sum_{k=1}^{n}e^{x_k} &=& \frac{\partial}{\partial x_i}(e^{x_1} + e^{x_2} + \ldots + e^{x_i} + \ldots + e^{x_n}) \\
&=& \displaystyle \frac{\partial}{\partial x_i}e^{x_1} + \frac{\partial}{\partial x_i}e^{x_2} + \ldots + \frac{\partial}{\partial x_i}e^{x_i}
+ \ldots + \frac{\partial}{\partial x_i}e^{x_n} \\
&=& 0 + 0 + \ldots + e^{x_i} + \ldots + 0 \\
&=& e^{x_i}
\end{eqnarray}
\]
同様に、\( \displaystyle \frac{\partial}{\partial x_j} \sum_{k=1}^{n}e^{x_k} = e^{x_j} \)となる。
\( Z = \displaystyle \sum_{k=1}^{n}e^{x_k} \)と置くと、\( f_i(x) = \displaystyle \frac{e^{x_i}}{Z} \)となるため、\(i=j\)の場合、
\[
\begin{eqnarray}
\displaystyle \frac{\partial}{\partial x_i}f_i(x) &=& \frac{\partial}{\partial x_i}\frac{e^{x_i}}{ \displaystyle \sum_{k=1}^{n}e^{x_k} } \\
&=& \displaystyle \frac{\partial}{\partial x_i} \frac{e^{x_i}}{Z} \\
&=& \displaystyle \frac{ \displaystyle \frac{\partial}{\partial x_i}e^{x_i} \times Z – e^{x_i} \times \frac{\partial}{\partial x_i}Z }{Z^2} \\
&=& \displaystyle \frac{ \displaystyle \frac{\partial}{\partial x_i}e^{x_i} \times Z – e^{x_i} \times \frac{\partial}{\partial x_i}\displaystyle \sum_{k=1}^{n}e^{x_k} }{Z^2} \\
&=& \displaystyle \frac{e^{x_i} \times Z – e^{x_i} \times e^{x_i}}{Z^2} \\
&=& \displaystyle \frac{e^{x_i} \times Z}{Z^2} – \frac{e^{x_i} \times e^{x_i}}{Z^2} \\
&=& \displaystyle \frac{e^{x_i}}{Z} – \left( \frac{e^{x_i}}{Z} \right)^2 \\
&=& f_i(x) – (f_i(x))^2 \\
&=& f_i(x)(1 – f_i(x))
\end{eqnarray}
\]
また、\(i≠j\)の場合、
\[
\begin{eqnarray}
\displaystyle \frac{\partial}{\partial x_j}f_i(x) &=& \frac{\partial}{\partial x_j}\frac{e^{x_i}}{ \displaystyle \sum_{k=1}^{n}e^{x_k} } \\
&=& \displaystyle \frac{\partial}{\partial x_j} \frac{e^{x_i}}{Z} \\
&=& \frac{ \displaystyle \frac{\partial}{\partial x_j}e^{x_i} \times Z – e^{x_i} \times \frac{\partial}{\partial x_j}Z }{Z^2} \\
&=& \displaystyle \frac{ 0 \times Z – \displaystyle e^{x_i} \times \frac{\partial}{\partial x_j}\displaystyle \sum_{k=1}^{n}e^{x_k} }{Z^2} \\
&=& \displaystyle \frac{ 0 – \displaystyle e^{x_i} \times e^{x_j} }{Z^2} \\
&=& – \displaystyle \frac{\displaystyle e^{x_i}}{Z} \times \frac{\displaystyle e^{x_j}}{Z} \\
&=& -f_i(x)f_j(x)
\end{eqnarray}
\]
まとめると、\(f_i(x)\) を\(x\)について偏微分すると、以下のようになる。
\[
\begin{eqnarray}
\displaystyle \frac{\partial}{\partial x_j}f_i(x) = \left\{ \begin{array}{l} f_i(x)(1 – f_i(x)) (i=jの場合)\\ -f_i(x)f_j(x) (i≠jの場合)\end{array} \right.
\end{eqnarray}
\]
要点まとめ
- 以下の式で表現される関数をソフトマックス関数といい、ディープラーニングの活性化関数の1つとして利用される。
\[
\begin{eqnarray}
f_i(x) = \displaystyle \frac{e^{x_i}}{ \displaystyle \sum_{k=1}^{n}e^{x_k} }
\end{eqnarray}
\] - ソフトマックス関数は、\(n\)個のデータがあるときに、その合計を\(1\)(\(100\)%)になるように調整してくれるため、多クラス分類を行うニューラルネットワークの出力層の活性化関数でよく利用される。
- ソフトマックス関数\(f_i(x)\) を\(x\)について偏微分すると、以下のようになる。
\[
\begin{eqnarray}
\displaystyle \frac{\partial}{\partial x_j}f_i(x) = \left\{ \begin{array}{l} f_i(x)(1 – f_i(x)) (i=jの場合)\\ -f_i(x)f_j(x) (i≠jの場合)\end{array} \right.
\end{eqnarray}
\]