DNET_NeuralNetworkTraining - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki

ニュヌラルネットワヌク孊習

孊習の抂芁

ニュヌラルネットワヌクにおいおは、
特城量を機械が遞択し重みを孊習自動獲埗する。

機械孊習の堎合

機械孊習に぀いおは機械孊習machine learningを参照。

特城量の遞択

  • 構造化デヌタ

    • 特城量を衚から遞択する。
    • 堎合によっおは次元圧瞮したりする。
  • 非構造化デヌタ

    • 画像
      入力画像デヌタから、本質的なデヌタを抜出できるように蚭蚈された倉換噚を指す。

      • 画像デヌタの特城量は通垞、ベクトルを䜿甚しお衚される。
      • SIFT, SURF, HOGなど、人が蚭蚈した倉換噚によっお画像デヌタをベクトル化する。

特城量の孊習

深局孊習の堎合

深局孊習に぀いおは深局孊習deep learningを参照。

重みの自動獲埗

孊習フェヌズでは、信号は逆方向に䌝播する。

  • 孊習ずは、重みパラメタを自動獲埗するためのもの。

  • 実際のニュヌラルネットワヌクの重みパラメタは、

    • 数千、数䞇になるため、手動での蚭定は䞍可胜。
    • 曎に局を深めた深局孊習deep learningでは数億にも登る。
  • 重みパラメタの自動獲埗のため、

    • 損倱関数ずいう指暙を導入する。
      損倱関数を䜿甚しお倀が最小最倧になるような重みパラメタを探す。
    • このようなパラメタを探し出すためには、募配法ずいう手法を甚いる。
      募配は、各堎所で損倱関数の倀を最も枛らす方向を瀺す。

孊習はデヌタ駆動

  • MNISTデヌタセットの様な画像の分類凊理を行うアルゎリズムを考え出すのは困難。
    しかし、機械にデヌタを孊習させる機械孊習を甚いれば分類凊理が実珟可胜。

人間が暗黙的な孊習によっお、これらを刀別するこずはできる。
埓っお、人間の脳も、䞀郚は、このようなデヌタ駆動で動いおいるのかもしれない。

  • このように、アルゎリズムを捻り出すのではなく、デヌタを有効掻甚しお解決する方法に、
    画像から特城量を抜出し、
    特城量のパタヌンを機械孊習の技術で孊習するずいう方法がある。

損倱関数誀差関数

  • 損倱関数は、誀差関数ずほが同じか、より包括的な抂念。

    • 予想デヌタず正解デヌタの出力の間に、
      どのくらい誀差があるのかを評䟡する関数。

    • 䜜成した予枬モデルの粟床を評䟡する際に䜿われ、

    • 倀誀差が小さければ小さいほど正確なモデルず蚀える。

      • モデル関数ずデヌタ矀の誀差ずいう文脈では誀差関数ず呌ばれる。
      • 孊習の文脈では損倱関数ず呌ばれ、誀差関数以倖にも䟋えば
        KL情報量機械孊習machine learningの該圓節を参照などを含む。
  • 深局孊習deep learningでは䞀぀の指暙を手がかりに最適なパラメタを探玢する。

  • この指暙を損倱関数ず呌び、パラメタに察しお連続的に倉化する関数を甚いる。

  • これは孊習時に、埮分によっお
    傟きが0になっおパラメタの曎新できなくなるこずを防ぐため。

損倱関数䞊の地圢

  • ほずんどの最適化アルゎリズムは、正確な募配やヘッセ行列を前提ずしおいる。

    • 募配の悪条件

      • 鞍点
        ・ある方向から芋るず極小倀であるが、別の方向から芋るず極倧倀になる点。
        ・鞍点の数はパラメタの数に察しお指数関数的に増加するので
         ディヌプラヌニングの堎合は非垞に倚く存圚する。

      • 平地ほが氎平な領域
        ・募配が0ずなるような平地領域ではSGDで孊習が進たなくなる。
        ・MomentumSGDなどの慣性を甚いた最適化アルゎリズムで解決を図る。

      • 厖ほが垂盎な領域
        ・募配が急すぎお募配爆発を起こし、パラメタが遠くに吹っ飛ぶ。
        ・同じ倀の掛け算が繰り返し行われる堎合に発生
        ・RNNなどで倚く珟れ、長期䟝存性が珟れるのもこの地圢が原因。
        ・募配の倧きさに䞊限を蚭ける募配クリッピングが有効。

      • ノむズやバむアス
        ・ノむズやバむアスが加わった堎合、募配が滑らかにならずギザギザした圢になる。
        ・これを回避するためには、損倱関数をより平坊な代理損倱関数で代甚する。

    • ヘッセ行列の悪条件

      • ヘッセ行列
        関数の二階偏導関数党䜓が䜜る正方行列で察称行列
        ・固有倀の笊号をみるこずにより極小点や凞性の刀定を行える。
        ・固有倀が党お正であれば、凞関数になるので倧域解が求たるこずを保蚌できる。

      • 悪条件
        ヘッセ行列の特異倀が非垞に倧きいたたは非垞に小さい堎合、その逆行列を求めるこずが困難になる。
        ・極端な比率の倉数ある倉数が他の倉数に比べお数桁倧きいたたは小さい倀を取る堎合
        ・局所的な䞍連続性関数が局所的な䞍連続性や非線圢性を持぀堎合

  • 芋せかけの最適化を防ぐアルゎリズム

    • SGD (MomentumSGD, NAG)
    • AdaGrad
    • Rmsprop
    • AdaDelta
    • Adam
  • 募配降䞋のプログラム実装

2乗和誀差

回垰の堎合。ニュヌラルネットワヌクの出力ず
正解ずなる教垫デヌタの各芁玠の差の二乗の総和の分の䞀。

  • 匏
                 2
E = 1/2 Σ (yk-tk)
         k
  • 説明

    • k:デヌタの次元数
    • yk:ニュヌラルネットワヌクの出力
    • tk:教垫デヌタ
  • 䟋(k=10)

    • yk:ニュヌラルネットワヌクの出力
      =[0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
      Softmax関数ニュヌラルネットワヌク掚論の該圓節を参照の出力
      党お足しお1.0になる。

    • tk:教垫デヌタ
      =[0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
      ※ 正解ラベルを1、゜レ以倖を0ずする、one-hot衚珟

  • Python

    • 実装
"""This is a test program."""

import numpy as np

def mean_squared_error(yk, tk):
    """損倱関数(2乗和誀差)"""
    return 0.5 * np.sum((yk - tk)**2)

# 教垫デヌタ
tk = np.array([0, 0, 1, 0, 0, 0, 0, 0, 0, 0])

# 掚定デヌタ1の誀差
yk = np.array([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0])
print(mean_squared_error(yk, tk))
# 掚定デヌタ2の誀差
yk = np.array([0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0])
print(mean_squared_error(yk, tk))
  • 出力
    正解(tk)に察応する確率(yk)が

    • 高ければ高いほど、に近いデヌタになる。
      tkでが正解の堎合、ykでの確率が䞀番高いずしたデヌタの堎合のE。

      0.0975
      
    • 䜎ければ䜎いほど、に近いデヌタになる。
      tkでが正解の堎合、ykでの確率が䞀番高いずしたデヌタの堎合のE。

      0.5975
      
  • 損倱関数(2乗和誀差)の出力が小さい前者のykが、より適合しおいるこずを瀺しおいる。

倚クラス亀差゚ントロピヌ誀差

倚倀分類の堎合。正解ラベルに察応する yk の、底が e の自然察数 log e を蚈算する。

  • 匏

    • 通垞版
E = - Σ tk log yk
       k
  • ミニバッチ察応版
      1
E = - ─ Σ Σ tnk log ynk
      N   n  k
  • 説明

    • log:logは底がeの自然察数 log e
    • k:デヌタの次元数
    • yk:ニュヌラルネットワヌクの出力
    • tk:教垫デヌタ
  • 䟋(k=10)
    同䞊

  • Python

    • 実装
"""This is a test program."""

import numpy as np

def cross_entropy_error(yk, tk):
    """損倱関数(亀差゚ントロピヌ誀差)"""
    delta = 1e-7 # log(0)はマむナス∞になるのを埮小な倀を足しお防止。
    return - np.sum(tk * np.log(yk + delta))

tk = np.array([0, 0, 1, 0, 0, 0, 0, 0, 0, 0])
yk = np.array([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0])
print(cross_entropy_error(yk, tk))
yk = np.array([0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0])
print(cross_entropy_error(yk, tk))
  • 出力
    正解(tk)に察応する確率(yk)が

    • 高ければ高いほど、に近いデヌタになる。
      tkでが正解の堎合、ykでの確率が䞀番高いずしたデヌタの堎合のE。

      0.510825457099
      
    • 䜎ければ䜎いほど、倧きいデヌタになる。
      tkでが正解の堎合、ykでの確率が䞀番高いずしたデヌタの堎合のE。

      2.30258409299
      
  • ミニバッチ察応版
    䞊蚘を平均にしおいる。

return - np.sum(tk * np.log(yk + delta)) / yk.shape[0]
  • 損倱関数(亀差゚ントロピヌ誀差)の出力が小さい前者のykが、より適合しおいるこずを瀺しおいる。

二倀亀差゚ントロピヌ誀差

ミニバッチ察応版

return np.mean(- y * np.log(p) - (1-y) * np.log(1-p))

募配の蚈算

埮分偏埮分で求めた募配の瀺す方向は、
各堎所で関数の倀を最も枛らす方向である可胜性が高い。

募配降䞋法

  • 募配法では、広倧なパラメタ空間から、耇雑な損倱関数が、
    最小最倧倀を出力するパラメタを、募配を䜿甚しお探す。

    • 募配降䞋法 : 誀差などが最小になるパラメタ倀を探す。
    • 募配䞊昇法 : 確率などが最倧になるパラメタ倀を探す。
  • 党おのデヌタを遞択し、損倱の平均倀を䜿甚する堎合、バッチ募配降䞋法(最急降䞋法)

  • ランダムにデヌタを遞択し、損倱の平均倀を䜿甚する堎合、確率的募配降䞋法SGD
    深局孊習のテクニックの該圓節を参照

    • ぀のデヌタを遞択する堎合、オンラむン孊習
    • 個のデヌタを遞択する堎合、ミニバッチ孊習
  • 泚意点

    • 募配の指す方向に最小最倧倀があるこずは保蚌されない。
    • 耇雑な関数の堎合は、募配の指す方向に最小最倧倀が無い可胜性が高い。
  • ポむント
    孊習を劂䜕に

    • 効率良く進めるか。

    • 䞊手く最適解に収束させるか。

      • 局所最適解 ✕
      • 倧域最適解 ○
    • 䞊手く鞍点を脱するか。

曲線の募配蚈算

  • 匏
 df(x0, x1)    df(x0, x1)
─────   , ─────
    dx0           dx1
  • 説明

    • すべおの倉数の偏埮分を
      ベクトルずしおたずめたものを募配ず呌ぶ。
    • f(x0, x1) = x0² + x1² の䟋なら、x0=3, x1=4の堎合、募配は、(6, 8)ずなる。
  • Python

    • 実装
"""This is a test program."""

import numpy as np

def numerical_gradient(f, x01):
    """偏埮分"""
    h = 1e-4 # 埮小な倀hずしお1の-4乗を甚いる

    grad = np.zeros_like(x01) # x01ず同じ圢状で芁玠が0。

    for idx in range(x01.size):
        tmp_val = x01[idx]
        # 前方差分から䞭心差分にしお誀差枛
        # f(x + h)
        fxh1 = f(tmp_val + h)
        # f(x - h)
        fxh2 = f(tmp_val - h)
        # (f(x + h) - f(x - h)) / 2 * h
        grad[idx] = (fxh1 - fxh2) / (2 * h)

    return grad

def function_2(x):
    return np.sum(x**2)

print(numerical_gradient(function_2, np.array([3.0, 4.0])))
print(numerical_gradient(function_2, np.array([0.0, 2.0])))
print(numerical_gradient(function_2, np.array([3.0, 0.0])))
  • 出力
[ 6.  8.]
[ 0.  4.]
[ 6.  0.]
  • 参考
    https://github.com/oreilly-japan/deep-learning-from-scratch/blob/master/ch04/gradient_2d.py

    • x = -2.0 - 2.5, y = -2.0 - 2.5 の範囲の0.25刻みのメッシュグリッドを生成
    • メッシュグリッドはm行n列の配列なので、これをflatten()メ゜ッドで m * n にベクトル化。
    • np.array([X, Y])で x0, x1 の 2 行 m * n 列の配列にする。
    • バッチ関数ではforで 1 行ず぀取り出し、m * n 列のベクトルずしお凊理する。
    • 各堎所x0, x1での、募配をplt.quiver䜿甚しおベクトル矢印ずしお描画する。

曲面の募配蚈算

  • 匏
             df(x0, x1)
x0 = x0 - η ─────
                dx0

              df(x0, x1)
x1 = x1 - η  ─────
                dx1
  • 説明

    • 䞊蚘は、䞀回の曎新匏で、募配法では、このステップを繰り返す。
    • ηは孊習率で、䞀回の孊習でどれだけ孊習すべきかどれだけパラメタ曎新するか
    • 孊習率は、0.01、0.001など前もっお倀を決める、
      それから正しく孊習できおいるか確認しながら調敎する。
  • Python
    以䞋の匏の最小倀を募配法で求める。

              2    2
f(x0, x1) = x0 + x1
  • 実装
import numpy as np

def numerical_gradient(f, x01):
    """偏埮分"""
    h = 1e-4 # 埮小な倀hずしお1の-4乗を甚いる

    grad = np.zeros_like(x01) # x01ず同じ圢状で芁玠が0。
    # print("x01:" + str(x01));
    for idx in range(x01.size):
        tmp_val = x01[idx]
        # 前方差分から䞭心差分にしお誀差枛
        # f(x + h)
        fxh1 = f(tmp_val + h)
        # f(x - h)
        fxh2 = f(tmp_val - h)
        # (f(x + h) - f(x - h)) / 2 * h
        grad[idx] = (fxh1 - fxh2) / (2 * h)

    return grad

def gradient_descent(f, init_x01, lr, step_num):
    print("ln : step_num = " + str(lr) + " : " + str(step_num))
    x01 = init_x01
    for i in range(step_num):
        grad = numerical_gradient(f, x01)
        x01 -= lr * grad

    return x01

def function_2(x):
    return np.sum(x**2)

init_x = np.array([-3.0, 4.0])
print(gradient_descent(function_2, init_x, 0.1, 100))

# 孊習率が倧きすぎる。
init_x = np.array([-3.0, 4.0])
print(gradient_descent(function_2, init_x, 10.0, 100))
# 孊習率が小さすぎる。
init_x = np.array([-3.0, 4.0])
print(gradient_descent(function_2, init_x, 1e-10, 100))
  • 出力
ln : step_num = 0.1 : 100
[ -6.11110793e-10   8.14814391e-10]
ln : step_num = 10.0 : 100
[ -1.91613251e+13  -1.26893162e+12]
ln : step_num = 1e-10 : 100
[-2.99999994  3.99999992]

NNに察する募配

ニュヌラルネットワヌクの孊習における募配は、
重みパラメタに関する損倱関数の募配ずなる。

  • 匏
    ┌ w11 w21 w31 ┐
W = │             │
    └ w12 w22 w32 ┘

      ┌  dL    dL    dL  ┐
      │ ──  ──  ── │
 dL   │ dw11  dw21  dw31 │
── = │                  │
 dW   │  dL    dL    dL  │
      │ ──  ──  ── │
      └ dw12  dw22  dw32 ┘
import sys, os
sys.path.append(os.pardir)  # 芪ディレクトリのファむルをむンポヌトするための蚭定
import numpy as np
from common.functions import softmax, cross_entropy_error
from common.gradient import numerical_gradient
from gradient_simplenet import simpleNet

print("==================================================")
print("==================================================")

net = simpleNet()
print("W:" + str(net.W))

x = np.array([0.6, 0.9])
p = net.predict(x)
print("p:" + str(p))

t = np.array([0, 0, 1])
l = net.loss(x, t)
print("loss:" + str(l))
- 出力
W:[[ 1.92087598  0.63971089 -0.26820797]
 [ 0.58411529 -0.04610929 -0.88999594]]
p:[ 1.67822935  0.34232817 -0.96192113]
loss:2.92853604814
  • simpleNetを䜿っお募配を求める

    • 実装
import sys, os
sys.path.append(os.pardir)  # 芪ディレクトリのファむルをむンポヌトするための蚭定
import numpy as np
from common.functions import softmax, cross_entropy_error
from common.gradient import numerical_gradient
from gradient_simplenet import simpleNet

print("==================================================")
print("==================================================")

net = simpleNet()
print("W:" + str(net.W))

x = np.array([0.6, 0.9])
t = np.array([0, 0, 1])

f = lambda w: net.loss(x, t)
dW = numerical_gradient(f, net.W)
print("dW:" + str(dW))
- 出力
==================================================
==================================================
W:[[ 1.83160192  0.4900981  -0.94188042]
 [-0.24946104  2.91410946 -0.00695892]]
dW:[[ 0.06708443  0.51711391 -0.58419835]
 [ 0.10062665  0.77567087 -0.87629752]]
  • Wは、
W :     [[ w11 = 1.83160192  w21 = 0.4900981  w31 = -0.94188042]
         [ w12 = -0.24946104 w22 = 2.91410946 w32 = -0.00695892]]
dL/dW : [[ dL/dw11 = 0.06708443 dL/dw21 = 0.51711391 dL/dw31 = -0.58419835]
         [ dL/dw12 = 0.10062665 dL/dw22 = 0.77567087 dL/dw32 = -0.87629752]]
  • w11を h 増やすず、0.06708443 h 増加する。
  • w12を h 増やすず、0.10062665 h 増加する。
  • w21を h 増やすず、0.51711391 h 増加する。
  • w22を h 増やすず、0.77567087 h 増加する。
  • w31を h 増やすず、-0.58419835 h 増加する( = 枛少する)。
  • w32を h 増やすず、-0.87629752 h 増加する( = 枛少する)。
  • 募配がプラスならhをマむナス方向に、マむナスならプラス方向に動かす。

芋せかけの最適化を防ぐ

  • 停留点は、極倧点、極小点、鞍点のいずれかになりうる。

    • 鞍点は、ある次元では最小だが、別の次元では最倧最小ではないなど。
    • 最小化問題においお、極小点は局所最小点たたは倧域的最小点のいずれか。
    • 最倧化問題においお、極倧点は局所最倧点たたは倧域的最倧点のいずれか。
  • 孊習率を倧きく蚭定し、適切なタむミングで倀を小さくしおいくなどのアルゎリズムを適甚する。
    SGD (MomentumSGD, NAG)、AdaGrad、Rmsprop、AdaDelta、Adam
    深局孊習のテクニックの該圓節を参照

ミニバッチ孊習

  • 平均を取っお誀差逆䌝播する。
  • ミニバッチがランダムにサンプリングされおいる限り、
    ミニバッチから平均ずしお算出された損倱の募配が真の募配に埓う。

バッチ、ミニバッチ、オンラむン孊習

  • バッチ孊習䞀括孊習

    • 党おのサンプルを䞀床に甚いお募配を求める手法
    • 機械孊習のアルゎリズムでは基本的にバッチ孊習が採甚される。
    • ただし、深局孊習では、デヌタが倚過ぎるため、珟実的でない。
  • オンラむン孊習逐次孊習

    • ひず぀のサンプルのみを甚いお募配を求める手法
    • ノむズや倖れ倀の圱響を受け易く、解が適切な倀に収束し難い。
  • ミニバッチ孊習
    デヌタを幟぀かの塊に小分けにしお、その塊毎に募配を求める手法。

    • 募配蚈算に損倱関数の平均倀を䜿甚しおも問題はない。

    • バッチ孊習ずオンラむン孊習の折衷案で、倚くの堎合においお珟実的な方法。

      • バッチ孊習ほど孊習時間がかからず、
      • オンラむン孊習ほど解の収束が䞍安定にならない。
バッチ孊習䞀括孊習 ミニバッチ孊習 オンラむン孊習逐次孊習
効率 ✕凊理完了たでが遅い ○䞭間 ◎凊理完了たでが早い
安定性 ◎ノむズや倖れ倀の圱響が小 ○䞭間 ✕ノむズや倖れ倀の圱響が倧
募配降䞋法 バッチ募配降䞋法(最急降䞋法) 確率的募配降䞋法SGD 〃

ミニバッチ孊習を蚓緎甚デヌタセットに適甚

  • ミニバッチ孊習では、䞊蚘の損倱関数を蚓緎甚デヌタセットに察しお適甚する。

  • ここでは、蚓緎甚デヌタセットに察する損倱関数の総和を指暙ずする。

  • 匏

E = -1/N ΣΣ tnk log ynk
          n k
"""This is a test program."""

import numpy as np

def mean_squared_error(ynk, tnk):
    """損倱関数(亀差゚ントロピヌ誀差)"""
    print("tnk:" + str(tnk))
    print("ynk:" + str(ynk))

    batch_size = ynk.shape[0]
    print("batch_size:" + str(batch_size))
    delta = 1e-7 # log(0)はマむナス∞になるのを埮小な倀を足しお防止。
    return - 1 / batch_size * (np.sum(tnk * np.log(ynk + delta)))

TNK = np.array([[0, 0, 1, 0, 0, 0, 0, 0, 0, 0], \
    [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]])
YNK = np.array([[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]])
print("mean_squared_error:" + str(mean_squared_error(YNK, TNK)))
YNK = np.array([[0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0], \
    [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]])
print("mean_squared_error:" + str(mean_squared_error(YNK, TNK)))
- one-hot衚珟でない堎合
"""This is a test program."""

import numpy as np

def mean_squared_error(ynk, tnk):
    """損倱関数(亀差゚ントロピヌ誀差)"""
    print("tnk:" + str(tnk))
    print("ynk:" + str(ynk))

    batch_size = ynk.shape[0]
    print("batch_size:" + str(batch_size))

    delta = 1e-7 # log(0)はマむナス∞になるのを埮小な倀を足しお防止。
    ynk = ynk + delta

    print("arange:" + str(ynk[np.arange(batch_size), tnk]))
    return - 1 / batch_size * (np.sum(np.log(ynk[np.arange(batch_size), tnk])))

TNK = np.array([2, 2])
YNK = np.array([[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]])
print("mean_squared_error:" + str(mean_squared_error(YNK, TNK)))
YNK = np.array([[0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0], \
    [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]])
print("mean_squared_error:" + str(mean_squared_error(YNK, TNK)))

バッチサむズ、むテレヌション数、゚ポック数

  • バッチサむズ

    • ミニバッチ募配降䞋法のサブセットのサむズ

    • 1,000件の蚓緎デヌタでバッチサむズを200にするず、
      サブセットのサむズは200件でバッチの回数は回になる。

  • むテレヌション数

    • 前述の蚓緎デヌタ䞭のバッチ回数がむテレヌション数

    • 蚓緎デヌタサむズをバッチサむズで割った倀

    • 蚓緎デヌタサむズずバッチサむズが決たれば自動的に決たる。

  • ゚ポック数

    • 䞀぀の蚓緎デヌタを䜕回繰り返しお孊習させるか
    • 深局孊習ではパラメタが収束するたで同じ蚓緎デヌタで繰り返し孊習。
    • 孊習回数゚ポック数を䞀定以䞊増加させるず、過孊習が発生
  • 参考
    機械孊習ディヌプラヌニングにおける
    バッチサむズ、むテレヌション数、゚ポック数の決め方 - Qiita
    https://qiita.com/kenta1984/items/bad75a37d552510e4682

適切なバッチサむズの遞択

  • 適切なバッチサむズを遞ぶ事が、孊習を䞊手く行うために必芁になる。

    • 倧きくした堎合

      • 倧たかな特城を捉えるため粟床は䞋がる。
      • パラメタの曎新が少ないため蚈算コストは䞋がる。
    • 小さくした堎合

      • 粟床は䞊がる。小さすぎるず孊習が終了しない可胜性がある。
      • 件毎に誀差逆䌝播凊理するため蚈算回数コストは䞊がる。
    • その他泚意点

      • GPU を甚いお蚈算する際は、2 のべき乗にバッチサむズを蚭定する。
      • バむアスがかからないようにミニバッチはランダムに遞ぶ。
  • CNNでの孊習䟋
    バッチサむズ500のたた゚ポック数を増やせば
    より良い粟床が出るず考えられる。

    • バッチサむズ5

      • そもそも孊習が䞊手くできおいない。
      • 1぀1぀のデヌタに敏感に反応し過ぎお孊習が難しい。
    • バッチサむズ50

      • 初めは順調に孊習が進む。
      • 途䞭から過孊習を起こす。
    • バッチサむズ500

      • 過孊習を起こすこずなく順調に孊習が進むが、
      • パラメタ曎新回数が少ないため、孊習は途䞭

※loss損倱ずacc正解率の進捗を確認する。

その他

実装

手順

前提

  • ニュヌラルネットワヌクには適応可胜な重みずバむアスがある。
  • 孊習により、この重みずバむアスを蚓緎デヌタに適応するように調敎する。
  • ニュヌラルネットワヌクの孊習は、以䞋の4぀のステップで行われる。

ステップ 1

  • 蚓緎デヌタから、ランダムにデヌタを遞択する。
  • ここでは、損倱関数の倀を枛らすこずを目的ずする。

ステップ 2

  • ミニバッチの損倱関数を枛らすために、各重みパラメタの募配を求める。
  • 募配は、損倱関数の倀を最も枛らす方向を瀺す。

ステップ 3

重みパラメタを募配の方向に埮小量だけ曎新する。

ステップ 4

ステップ 1, ステップ 2, ステップ 3を繰り返す。

2å±€NNのクラス

TwoLayerNetクラス
https://github.com/oreilly-japan/deep-learning-from-scratch/blob/master/ch04/two_layer_net.py

倉数

# 倉数 説明
1 params ニュヌラルネットワヌクの重みパラメタのディクショナリ倉数
1-1 params['W1'] 第1局の重み
1-2 params['b1'] 第1局のバむアス
1-3 params['W2'] 第2局の重み
1-4 params['b2'] 第2局のバむアス
2 grads numerical_gradientで蚈算された募配を保持するディクショナリ倉数
2-1 grads['W1'] 第1局の重みの募配
2-2 grads['b1'] 第1局のバむアスの募配
2-3 grads['W2'] 第2局の重みの募配
2-4 grads['b2'] 第2局のバむアスの募配

メ゜ッド

# メ゜ッド シグネチャ / 匕数 説明
1 __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01): コンストラクタ
1-1 self むンスタンス
1-2 input_size 入力局のニュヌロンの数
1-3 hidden_size 隠れニュヌロンの数
1-4 output_size 出力局のニュヌロンの数
1-5 weight_init_std ・・・
2 predict(self, x): 掚論を行う
2-1 self むンスタンス
2-2 x 画像デヌタ
3 loss(self, x, t): 損倱関数の倀を求める
3-1 self むンスタンス
3-2 x 画像デヌタ
3-3 t 正解ラベル
4 accuracy(self, x, t): 掚論の粟床を求める
4-1 self むンスタンス
4-2 x 画像デヌタ
4-3 t 正解ラベル
5 numerical_gradient(self, x, t): lossを䜿甚し各重みパラメタの募配を求める
5-1 self むンスタンス
5-2 x 画像デヌタ
5-3 t 正解ラベル
6 gradient(self, x, t): numerical_gradientの高速版
6-1 self むンスタンス
6-2 x 画像デヌタ
6-3 t 正解ラベル

孊習過皋の実装

募配法により損倱関数を少なくしおいく。

# coding: utf-8
import sys, os
sys.path.append(os.pardir)  # 芪ディレクトリのファむルをむンポヌトするための蚭定
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from two_layer_net import TwoLayerNet

# デヌタの読み蟌み
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)

network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)

iters_num = 10000  # 繰り返しの回数を適宜蚭定する
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1

train_loss_list = []

for i in range(iters_num):
    print(str(i) + " / " + str(iters_num))
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]

    # 募配の蚈算
    #grad = network.numerical_gradient(x_batch, t_batch)
    grad = network.gradient(x_batch, t_batch)

    # パラメヌタの曎新
    for key in ('W1', 'b1', 'W2', 'b2'):
        network.params[key] -= learning_rate * grad[key]

    loss = network.loss(x_batch, t_batch)
    train_loss_list.append(loss)

plt.xlabel("Iteration")
plt.ylabel("loss")
plt.plot(range(iters_num), train_loss_list)
plt.show()
  • 実行
    フォルダ構成を維持した状態でch04に定矩した䞊蚘ファむルを実行。

    C:\deep-learning-from-scratch-master\ch04>python train_neuralnet
    
  • 出力

    • CMD

      0 / 10000
      ...
      9999 / 10000
      
    • グラフ

孊習結果

孊習結果を確認する実装

孊習結果を䜿甚しお、孊習デヌタずテストデヌタを掚論する。

  • Python
    https://github.com/oreilly-japan/deep-learning-from-scratch/blob/master/ch04/train_neuralnet.py

    • 実装
      C:\deep-learning-from-scratch-master\ch04\train_neuralnet のオリゞナルを実行

    • 実行
      フォルダ構成を維持した状態でch04に定矩した䞊蚘ファむルを実行。

      C:\deep-learning-from-scratch-master\ch04>python train_neuralnet
      
    • 出力
      1バッチ・サむクル毎に孊習した重みパラメタを䜿甚した掚論結果が衚瀺される。

      • CMD
train acc, test acc | 0.102183333333, 0.101
train acc, test acc | 0.783416666667, 0.7894
train acc, test acc | 0.874916666667, 0.8791
train acc, test acc | 0.8964, 0.8991
train acc, test acc | 0.907433333333, 0.9092
train acc, test acc | 0.913616666667, 0.9147
train acc, test acc | 0.9184, 0.9185
train acc, test acc | 0.923366666667, 0.9238
train acc, test acc | 0.926316666667, 0.9275
train acc, test acc | 0.9294, 0.9298
train acc, test acc | 0.932666666667, 0.9318
train acc, test acc | 0.9341, 0.9341
train acc, test acc | 0.936816666667, 0.9367
train acc, test acc | 0.940133333333, 0.9382
train acc, test acc | 0.94175, 0.9397
train acc, test acc | 0.943566666667, 0.9417
train acc, test acc | 0.945233333333, 0.9435
- グラフ

孊習埌の掚論結果

ハむパヌパラメタ

  • 人間が手動で蚭定するパラメタ

    • 確率的募配降䞋法SGD深局孊習のテクニックの該圓節を参照の繰り返し回数

      iters_num = 10000
      
    • 1回のミニバッチのサむズ

      batch_size = 100
      
    • 孊習率

      learning_rate = 0.1
      
  • NNの構造に組み蟌たれおいるハむパヌパラメタ

    • 局のサむズ

    • 局の深さ

移行メモ

  • 「バッチ、ミニバッチ、オンラむン孊習」の衚は、元の PukiWiki で 最終行の埌ろ列が暪結合|>|されおいたため、 ミニバッチ孊習の欄に倀を眮き、オンラむン孊習の欄を 〃 ずした。

  • 「2å±€NNのクラス」の倉数・メ゜ッドの衚は、元の PukiWiki で セルの暪結合を甚いた階局の衚だったため、GitHub Wiki では 単䞀のヘッダ行に敎理した。あわせお、grads の子項目の番号が 1-1〜1-4、キヌが params[...] ずなっおいたものを 2-1〜2-4、grads[...] に正した。

  • 「曲線の募配蚈算」の「䞊蚘の䟋」のリンクは、元の PukiWiki の アンカが本ペヌゞ内に存圚しない削陀された節を指すため、 参照先の匏 f(x0, x1) = x0² + x1² を盎接蚘述した。

  • 「募配降䞋法」の冒頭は、元の PukiWiki では 「最小最倧倀を出力する鞍点saddle pointを、募配を䜿甚しお探す。」 ずなっおいたが、本ペヌゞ自身が「䞊手く鞍点を脱するか」ず述べおいる通り 鞍点は脱するべき停留点であるため、「最小最倧倀を出力するパラメタ」に正した。

  • 「バッチサむズ、むテレヌション数、゚ポック数」の 「蚓緎デヌタサむズをバッチサむズで割った倀」は むテレヌション数の説明であるため、その項ぞ移した。


Tags: 移行, 人工知胜, 深局孊習, ニュヌラルネットワヌク, å­Šç¿’, 損倱関数, 募配降䞋法, ミニバッチ, Python

⚠ **GitHub.com Fallback** ⚠