ソフトマックス関数

ソフトマックス関数

ソフトマックス関数

ソフトマックス関数の定義

 $n$ 次元の実数ベクトル
 
\[\boldsymbol{x}=\begin{bmatrix}
x_1\\x_2\\\vdots\\x_n\end{bmatrix}\]
が与えられたとき、
 
\[y_i=\frac{\exp(x_i)}{\displaystyle\sum_{i=1}^{n}\exp(x_i)}\]
で表される成分をもつ実数ベクトル
 
\[\boldsymbol{y}=\begin{bmatrix}
y_1\\y_2\\\vdots\\y_n\end{bmatrix}\]
を返す関数をソフトマックス関数とよびます。$\displaystyle u=\sum_{i=1}^{n}\exp(x_i)$ とおくと、
 
\[y_i=\frac{\exp(x_i)}{u}\]
と表せます。
 

ソフトマックス関数の性質

 $x_i$ を入力値、$y_i$ を出力値と考えると、入力値の大小関係はそのまま出力値に反映されます。すなわち、入力値について
 
\[x_1\lt x_2\lt x_3\]
であるときは、必ず
 
\[y_1\lt y_2\lt y_3\]
のようになります。実際にソフトマックス関数を実装して
 
\[\boldsymbol{x}=\begin{bmatrix}
x_1\\x_2\\x_3\end{bmatrix}
=\begin{bmatrix}1\\2\\3\end{bmatrix}\]
という値を入力してみましょう。

# リストA-1

# NumPyをインポート
import numpy as np

# ソフトマックス関数を定義
def softmax(x):
    u = np.sum(np.exp(x))
    return np.exp(x)/u

# x=(1,2,3)を入力
x = np.array([1, 2, 3])

# 出力値を計算
y = softmax(x)

print(y)
[0.09003057 0.24472847 0.66524096]

 実行結果を見ると、出力値 $y_i$ は
 
\[\boldsymbol{y}=\begin{bmatrix}
y_1\\y_2\\y_n\end{bmatrix}
=\begin{bmatrix}
\cfrac{\exp(x_1)}{\exp(x_1)+\exp(x_2)+\exp(x_3)}\\
\cfrac{\exp(x_2)}{\exp(x_1)+\exp(x_2)+\exp(x_3)}\\
\cfrac{\exp(x_3)}{\exp(x_1)+\exp(x_2)+\exp(x_3)}\end{bmatrix}
=\begin{bmatrix}
0.09003057\\0.24472847\\0.66524096\end{bmatrix}\]
となっていて、確かに $y_1\lt y_2\lt y_3$ を満たしています。

 ソフトマックス関数の定義から明らかなように、
 
\[\begin{align*}&0\lt y_i\lt 1\\[6pt]
&y_1+y_2+\cdots+y_n=1\end{align*}\]
という性質があるので、どのような値を入力しても出力値は確率分布の条件を満たしています。
 

ソフトマックス関数の微分

 ソフトマックス関数の定義式
 
\[y_i=\frac{\exp(x_i)}{u}\]
において、両辺に $u$ をかけると
 
\[uy_i=\exp(x_i)\]
となります。両辺を $x_i$ で微分すると、積の微分公式により
 
\[\frac{\partial u}{\partial x_i}y_i+u\frac{\partial y_i}{\partial x_i}=\exp(x_i)\]
 $\displaystyle u=\sum_{i=1}^{n}\exp(x_i)$ を $x_i$ で微分すると $\exp(x_i)$ だけが残るので、上式は
 
\[y_i\exp(x_i)+u\frac{\partial y_i}{\partial x_i}=\exp(x_i)\]
となります。したがって、
 
\[\frac{\partial y_i}{\partial x_i}=\frac{(1-y_i)\exp(x_i)}{u}\]
となりますが、$y_i=\exp(x_i)/u$ なので、
 
\[\frac{\partial y_i}{\partial x_i}=y_i(1-y_i)\tag{1}\]
という式を得ます。この式はシグモイド関数
 
\[f(x)=\frac{1}{1+e^{-ax}}\quad (a\gt 0)\]
の導関数
 
\[\frac{dy}{dx}=ay(1-y)\]
と同じ形をしています。つまり、$y_i$ の $x_i$ 軸方向に沿った勾配の様子はシグモイド関数 (下図 a = 1) のようになっているということです。

 Python シグモイド関数グラフ

 今度は $i\neq j$ として、
 
\[uy_i=\exp(x_i)\]
の両辺を $x_j$ で微分してみます。
 
\[\frac{\partial u}{\partial x_j}y_i+u\frac{\partial y_i}{\partial x_j}=0\]
 $\partial u/\partial x_j=exp(x_j)$ を用いて上式を整理すると
 
\[\frac{\partial y_i}{\partial x_j}=-y_iy_j\quad (i\neq j)\tag{2}\]
が得られます。(1) と (2) をまとめると
 
\[\frac{\partial y_i}{\partial x_j}=y_i(\delta_{ij}-y_j)\]
という式で表すことができます。$\delta_{ij}$ はクロネッカーのデルタとよばれる記号で、$i=j$ のときに $1$, $i\neq j$ のときは $0$ となることを意味しています。