5.2. 損失関数

  • ニューラルネットワークでは、一つの指標を手掛かりに最適なパラメータを探索する

  • ニューラルネットワークの指標は 損失関数 (loss function)

  • 損失関数は、ニューラルネットワークの性能の悪さを示す

5.2.1. 2乗和誤差 (mean squared error)

\[E = \frac{1}{2} \sum_{k}^{} (y_k-t_k)^2\]
[1]:
import numpy as np

def mean_squared_error(y, t):
    return 0.5 * np.sum((y-t)**2)
[2]:
# 「2」を正解とする
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]

# 「2」の確立が最も高い場合
y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
mean_squared_error(np.array(y), np.array(t))
[2]:
0.09750000000000003
[3]:
# 「7」の確率が最も高い場合
y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
mean_squared_error(np.array(y), np.array(t))
[3]:
0.5975
  • この値から、一つ目の損失関数が小さいことがわかる

5.2.2. 交差エントロピー誤差 (cross entropy error)

\[E = - \sum_{k}^{} t_k\log{y_k}\]
[4]:
def cross_entropy_error(y, t):
    delta = 1e-7
    return -np.sum(t * np.log(y + delta))
  • delta は、np.log(0) の計算時に-infにならないための防止策

[5]:
# 「2」を正解とする
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]

# 「2」の確立が最も高い場合
y = [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(y), np.array(t))
[5]:
0.510825457099338
[6]:
# 「7」の確率が最も高い場合
y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
cross_entropy_error(np.array(y), np.array(t))
[6]:
2.302584092994546

5.2.3. ミニバッチ学習

訓練データすべての損失関数の和は、交差エントロピー誤差の場合

\[E = -\frac{1}{N} \sum_{n}\sum_{k} t_{nk}\log{y_{nk}}\]
  • \(t_{nk}\)\(n\)個目のデータの、\(k\)番目の値のこと

  • \(y_{nk}\)はニューラルネットワークの出力

  • \(t_{nk}\)は訓練データ

訓練データすべてを計算するには時間がかかってしまうので、データの一部を選んで「近似」として学習させることを、ミニバッチ学習という。

[7]:
import sys, os
sys.path.append(os.path.abspath(os.path.join('..', 'sample')))

import numpy as np
from dataset.mnist import load_mnist # サンプルにあるPythonモジュール

(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)

print(x_train.shape)
print(t_train.shape)
(60000, 784)
(60000, 10)
[8]:
def cross_entropy_error(y, t):
    """
    交差エントロピー誤差を出力します

    Parameters
    ----------
    y : np.array
        ニューラルネットワークの出力
    t : np.array
        教師データ
    """
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)

    batch_size = y.shape[0]

    # 教師データがone-hot表現のとき
    # return -np.sum(t * np.log(y) / batch_size)

    # 教師データがラベルの場合
    return -np.sum(np.log(y[np.arange(batch_size), t])) / batch_size

5.2.4. なぜ損失関数を設定するのか

  • パラメータの微分(正確には勾配)を計算し、その値と損失関数の値を比較するため

  • 微分の値がマイナスであれば、重みパラメータをプラスに補正する

  • 微分の値がプラスであれば、重みパラメータをマイナスに補正する

  • 微分の値が0であれば、損失関数の値も変化しないので更新をストップする

5.2.4.1. なぜ認識制度ではないのか

例えば、100枚中32枚を正しく認識できたら、認識制度が32%になる。しかし、重みパラメータの値を少し変えただけでは認識制度が32%のままになる (32/100なので、細かい変化がつかめない)。仮に認識制度が向上しても、100枚中33枚、つまり33%と、値が整数でしか測れない。

一方、損失関数は100%中何%が外れだったのか(ざ、ざっくり過ぎる説明…)がわかる