台風で自宅に篭れるから勉強時間をとれるな..、と見積もってたのだけれども、
近所の多摩川がマジで溢れそうでそれどころではなく…。
時間が空いてしまったがゼロから作るDeepLearningを読んで実際に実装する作業を再開する。
今後、パラメータを更新していくのだが、どういう方針でパラメータを更新するか決めておく必要がある。
教師ありデータを使った学習を扱っている訳で、訓練データと対応する教師データが与えられている前提。
何かの学習をした結果のモデルの出力と教師データの差を「誤差」として、「誤差」が小さくなるように
パラメータを決めていこうという方針。
例えば手書き文字認識で言うところの「認識精度」を指標に使ってしまうと、
モデルの出力が微小に変化したところで「認識精度」は微小に変化しない状況が発生する。
「認識精度」が変化するときは一気に変化する。これではパラメータをどの方向にずらして良いかわからない。
※SVMの解説で非線形分離を行う決定境界を0/1損失で決めることの問題点に通じる。
非線形分離を行う決定境界も損失関数により微小な変化に追従して決めていく。
2乗和誤差,クロスエントロピー誤差
ということで誤差関数を導入する。
\(y_k\)はモデルの出力で、最終段でSoftMax関数を通してある。
まずは2乗和誤差。まぁ簡単で、正解と出力の差を2乗した値を足す。
\begin{eqnarray}
E = \frac{1}{2} \sum_{k=1}^N (y_k – t_k)^2
\end{eqnarray}
次にクロスエントロピー誤差。
\begin{eqnarray}
E = – \sum_{k=1}^N t_k \log y_k
\end{eqnarray}
どっちでも良いんじゃ..、と思う訳だけれども、非線形分離問題で決定境界を決めるときに、
正解をより正解として、誤りをより誤りとして表現できる誤差がより優秀なので、
クロスエントロピー誤差の方が適切ではある。
クロスエントロピー誤差の方は\(t_k\)がゼロの項はゼロになるので、\(t_k\)が1の項だけ計算すれば良い。
つまり、正解が1のケースについてのみ誤差値が発生する。
\(-\log y_k\)は\(y_k\)がゼロに近いと急激に値が大きくなる。
これにより、\(t_k=1\)なのにゼロに近い\(y_k\)が出力されたときに大きなペナルティを与えられる。
クロスエントロピー誤差関数の実装
バッチ(並列実行)対応のクロスエントロピー誤差関数。
1 2 3 4 5 6 7 8 |
def cross_entropy_error(y, t): if y.ndim == 1: t = t.reshape(1, t.size) y = y.reshape(1,y.size) batch_size = y.shape[0] delta = 10e-7 return -np.sum( t * np.log( y + delta)) / batch_size |
1次元のデータを与えてみる。
1 2 3 4 |
t1 = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0] y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0] cross_entropy_error(np.array(y1), np.array(t1)) # 0.5108239571007129 |
2次元のデータを与えてみる。
1 2 3 4 5 6 |
t2 = [ [0, 0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]] y2 = [[0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0], [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]] cross_entropy_error(np.array(y2), np.array(t2)) # 7.163167257532494 |
バッチ対応が簡単に書けるところがかなり美しい。