技術っぽいことを書いてみるブログ

PythonとかVue.jsとか技術的なことについて書いていきます。

ニューラルネットワークの学習について(損失関数編)

はじめに・・・

今回は、ニューラルネットワークの学習について記載していきますが、
損失関数や微分・勾配などの様々な要素が出てきますので、
何回かに分けてニューラルネットワークの学習について記載していきます。
今回は、損失関数について記載します。

ニューラルネットワークの学習とは

ニューラルネットワークは、下記のようなイメージで、
入力値から各ノードの計算を行い、出力値を得ますが、
その出力値が、正しい値を示す教師データになるような重みパラメータを得ることを言います。
f:id:where-is-wally:20190422215530p:plain

ニューラルネットワークの学習の手順とは

ニューラルネットワークの学習は、以下の手順で行います。

  1. ニューラルネットワークのミニバッチ実行する。
  2. 損失関数を導出する。
  3. 損失関数の値を減らすため、勾配を導出する。
  4. 重みパラメータの更新
    求めた勾配の値を基に重みパラメータを更新する
    1. ~4. を繰り返す

      ※今回は、損失関数について記載します。

損失関数とは

ニューラルネットワークの性能の悪さを示す値で、
どれだけ正しい値を示す教師データと離れているかを示す指標となります。
損失関数には、二乗和誤差や交差エントロピー誤差がありますが、
ここでの実装は、交差エントロピー誤差のみとします。

損失関数を求めるにあたり、
ニューラルネットワークの出力をy=[0.1, 0.6, 0.15, 0.05, 0, 0.1, 0, 0, 0, 0]とし、
教師データをt=[0, 1, 0, 0, 0, 0, 0, 0, 0, 0]とします。
教師データtは、2個目の要素が1なので、2個目の要素が正しいことを示しています。
一方で出力yは、1個目の要素が0.1なので、10%を示しており、
2個目の要素が0.6(60%)なので、ニューラルネットワークの答えとしては、
2個目の要素が正しいだろうということを示しています。

交差エントロピー誤差

交差エントロピー誤差の公式は、次の通りです。
f:id:where-is-wally:20190513203806p:plain
※公式の説明は、割愛します。実装を確認すればおおよそ理解してもらえると思います。

import numpy as np

#クロスエントロピー誤差
def cross_entropy_error(y, t):
    # 公式にはないが、np.log(0)は、マイナス無限大になるので、極小値をたす
    return -np.sum(t * np.log(y + 1e-7))

# 教師データ 正解は2個目の要素
t = np.array([0, 1, 0, 0, 0, 0, 0, 0, 0, 0])

# ニューラルネットワークの出力
y = np.array([0.1, 0.6, 0.15, 0.05, 0, 0.1, 0, 0, 0, 0])
error1 = cross_entropy_error(y, t)
print(error1)

# ニューラルネットワークの出力をより精度が高い想定にする
y = np.array([0.1, 0.8, 0.05, 0.05, 0, 0.0, 0, 0, 0, 0])
error2 = cross_entropy_error(y, t)
print(error2)

# ニューラルネットワークの出力をより精度が悪い想定にする
y = np.array([0.1, 0.5, 0.25, 0.05, 0.05, 0.05, 0, 0, 0, 0])
error3 = cross_entropy_error(y, t)
print(error3)

実行結果

0.510825457099338
0.22314342631421757
0.6931469805599654

教師データに近い場合は、交差クロスエントロピー誤差の値は小さく、
教師データに遠い場合は、交差クロスエントロピー誤差の値は大きくなっています。

交差エントロピー誤差のミニバッチ化

上記の交差エントロピー誤差では、一つの出力に対し、一つの教師データしか評価できません。
一方で、機械学習では膨大なデータを基に学習を行い、最適な重みパラメータを導出する必要があります。
この為、交差エントロピー誤差の導出も、多くのデータを対象に処理できるように実装する必要があります。

import numpy as np

#クロスエントロピー誤差
def cross_entropy_error_batch(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = t.resyape(1, y.size)

    batch_size = t.shape[0]
    return -np.sum(t * np.log(y + 1e-7)) / batch_size

y = np.array([
             [0.7, 0.05, 0.1, 0.15, 0, 0, 0, 0, 0, 0],
             [0.1, 0.6, 0, 0.15, 0, 0.1, 0, 0, 0.05, 0],
             [0, 0, 0.75, 0.1, 0, 0.1, 0, 0.05, 0, 0],
             [0, 0, 0.05, 0.8, 0, 0, 0.15, 0, 0, 0],
             [0, 0.15, 0, 0, 0.75, 0, 0, 0, 0.1, 0],
             [0, 0, 0, 0.05, 0.1, 0.65, 0.1, 0, 0.1, 0],
             [0.15, 0, 0, 0, 0, 0, 0.75, 0, 0.1, 0],
             [0, 0.05, 0, 0, 0, 0.05, 0.1, 0.7, 0.1, 0],
             [0, 0, 0, 0, 0, 0, 0, 0.1, 0.8, 0.1],
             [0.15, 0, 0, 0, 0, 0.05, 0.1, 0, 0, 0.7]
            ])
t = np.array([
            [1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
            ])

error = cross_entropy_error_batch(y, t)
print(error)

実行結果

0.3320965292574255

最後に・・・

ゴールデンウィーク10連休があったりして、ブログの更新が久々になってしまいました。
次回は、微分と勾配について書く予定です。

普段、社内SEとして、業務システムを構築しているのですが、
将来的に、その業務システムのデータとディープラーニングを利用して、パターンの発見や未来の予測などをしたいと思っています。
今はディープラーニングの基礎を学んでいる状態ですが、次のステップとして、フレームワークを使用したディープラーニングをしたいと考えております。
業務システムのデータを基に解析・予測などをするために適切なフレームワークがあれば、コメント頂けると助かります。

お読みいただき、ありがとうございました。