目的
この記事では、損失関数の紹介と簡単な実装サンプルについて記載する。
概念の説明と実装サンプル
ニューラルネットワークで使用する損失関数
ニューラルネットワークの学習とは、訓練データを基に意図した結果となる最適な重みパラメータを判別することを指す。
学習するためには、損失関数というニューラルネットワークの性能の悪さを表す指標を基準に、その値が最も小さくなる重みとなるように自己探索(最適な重みパラメータを探す)していくことになる。
ここでは、有名な損失関数である2乗和誤差、交差エントロピー誤差について、簡単なPython実装サンプルを使って解説する。
2乗和誤差の定義
2乗和誤差(mean squared error)は、残差平方和とも呼ばれ、ターゲットとなる2つの変数差の2乗を総和し、2で割った値を取る。
この2つの変数のうち \(y_{k}\) をニューラルネットワークの出力、もう1つの \(t_{k}\) を教師データ(訓練データ)と置く。
※ \(k\) はデータの次元数
2乗和誤差の実装サンプル
Python - AI : MNISTのダウンロード方法(手書き数字画像セットを取込む) で触れたMNISTデータセットを用いたと想定して、10個の要素からなるデータを例に解説する。
$ python
>>> y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
>>> t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
- \(k=10\) は、10個の要素からなるデータでMNISTで扱うデータ数(0~9の数字)
- \(y_{k}\) にあたる \(y\) は、ニューラルネットワークの出力でソフトマックス関数出力値(確率)
※ この出力値の算出処理については、Python - AI : MNISTを使ったニューラルネットワークの推論処理と実装サンプル> 推論処理のニューロン構成と関数定義 のpredict関数を参考。 - \(t_{k}\) にあたる \(t\) は、教師データでMNISTであらかじめ準備されている正解表す配列(1が正解)
- \(y\) と \(t\) は、それぞれの要素同士が対となっている
- 要素1:数字画像が0の確率が10%(0.1)→ 不正解(0)
- 要素2:数字画像が1の確率が5%(0.05)→ 不正解(0)
- 要素3:数字画像が2の確率が60%(0.6)→ 正解(1)
- 要素4:数字画像が3の確率が0%(0.0)→ 不正解(0)
- 要素5:数字画像が4の確率が5%(0.05)→ 不正解(0)
- 要素6:数字画像が5の確率が10%(0.1)→ 不正解(0)
- 要素7:数字画像が6の確率が0%(0.0)→ 不正解(0)
- 要素8:数字画像が7の確率が10%(0.1)→ 不正解(0)
- 要素9:数字画像が8の確率が0%(0.0)→ 不正解(0)
- 要素10:数字画像が9の確率が0%(0.0)→ 不正解(0)
上記 \((A)\) は、この要素別の \(y\) と \(t\) の差を2乗した総和を2で割ったものでPythonで書くと
0.5 * np.sum((y-t)**2)
となる。
これを関数で定義し、上記の \(y\) と \(t\) で実行してみる。
$ python
>>> import numpy as np
>>> def mean_squared_error(y, t):
... return 0.5 * np.sum((y-t)**2)
...
>>> y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
>>> t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
>>> mean_squared_error(np.array(y), np.array(t))
0.09750000000000003
正解である2が60%となり、上記mean_squared_errorの結果は、約0.0975となった。
試しにわざとはずして不正解である7が60%となる \(y\) で結果を見てみると
$ python
>>> import numpy as np
>>> def mean_squared_error(y, t):
... return 0.5 * np.sum((y-t)**2)
...
>>> y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
>>> t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
>>> mean_squared_error(np.array(y), np.array(t))
0.5975
結果は0.5975となり、約6倍(損失が6倍)まで大きくなってしまう。
ちなみに正解である2が100%となる下記 \(y\) だと、結果は0となり、損失が0(間違った予測し)ということになる。
>>> y = [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
>>> t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
>>> mean_squared_error(np.array(y), np.array(t))
0.0
交差エントロピー誤差の定義
交差エントロピー誤差(cross entropy error)は、クロスエントロピーとも呼ばれ、ターゲットとなる2つの変数のうち、一方を自然対数(底は \(e\))として双方の積総和にマイナスをかけた値を取る。
この2つの変数のうち \(y_{k}\) をニューラルネットワークの出力、もう1つの \(t_{k}\) を教師データ(訓練データ)とする。
※ \(k\) はデータの次元数
交差エントロピー誤差と実装サンプル
前項と同様に、10個の要素からなるデータを例に解説する。
$ python
>>> y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
>>> t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
\(y_{k}\)、\(t_{k}\) と同様に \(k=10\) となる \(y\) は、ソフトマックス関数の出力値で \(t\) は、正解のみ1、不正解は0を取る。
そして、上記 \((B)\) の \(t_{k}\) は、不正解が0となる9つは積も必ず0となる。 よって、結局は正解1である \(y_{k}\)、つまり0.6の自然対数にマイナスをかけた値である
前項でわざとはずした下記の結果であれば
となるため、結果(損失値)が高くなっていることが分かる。
これをPythonで書くと
delta = 1e-7
-np.sum(t * np.log(y + delta))
となる。
※ \(delta = 1e-7\) は、\(y_{k}\) が0となる \(\log(0)\) によってマイナスの無限大に発散しないよう微量なdeltaを足し込んでいる。
関数で定義し、上記の \(y\) と \(t\) で実行してみる。
$ python
>>> import numpy as np
>>> def cross_entropy_error(y, t):
... delta = 1e-7
... return -np.sum(t * np.log(y + delta))
...
>>> y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
>>> t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
>>> cross_entropy_error(np.array(y), np.array(t))
0.510825457099338
正解である2が60%となる上記cross_entropy_errorの結果は、約0.510となった。
わざとはずして不正解である2が10%となる \(y\) だと
$ python
>>> import numpy as np
>>> def cross_entropy_error(y, t):
... delta = 1e-7
... return -np.sum(t * np.log(y + delta))
...
>>> y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
>>> t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
>>> cross_entropy_error(np.array(y), np.array(t))
2.302584092994546
結果は約2.302となり、約4倍(損失が4倍)まで大きくなり、前項と同様に妥当な損失値が得られていることが分かる。
参考文献
- 斎藤 康毅(2018)『ゼロから作るDeep Learning - Pythonで学ぶディープラーニングの理論と実装』株式会社オライリー・ジャパン