Rabbit Challenge レポート(深層学習 DAY1)


1. 入力層~中間層

入力: $x_i$

重み: $w_i$

バイアス: $b$

総入力: $u = w_1x_1 + w_2x_2 + ... w_nx_n + b = Wx + b$

活性化関数: $f$

2. 活性化関数

活性化関数: $ f^{(l)}(u^{(l)}) = [f^{(l)}(u_1^{(l)}...u_j^{(l)})]$

中間層で用いられる活性化関数

ステップ関数

def step_function(x):
  if x > 0:
    return 1
  else:
    return 0

0~1の間を表現できず、線形分離可能なものしか学習しなかった

シグモイド関数

def sigmoid(x):
  return 1/1(+np.exp(-x))

ステップ関数では表現できない0~1の値を表すことができ、NN普及のひっかけとなった

大きな値では出力の変化が微弱なため、勾配消失問題を引き起こすことがあった

RELU関数

def relu(x):
  return np.maximum(0,x)

昨今最も使われている活性化関数

勾配消失問題の回避とスパース化に貢献することで良い結果をもたらしてくれる

3. 出力層

誤差関数

平均二乗誤差

$En(w) = \frac{1}{2}\sum_{j=1}^l(y_j-d_j)^2 = \frac{1}{2}||(y-d)||^2$

# 平均二乗誤差
def mean_squared_error(d, y):
    return np.mean(np.square(d - y)) / 2

交差エントロピー

$ En(w) = \ \sum_{i=1}^l d_i\log y_i$

# クロスエントロピー
def cross_entropy_error(d, y):
    if y.ndim == 1:
        d = d.reshape(1, d.size)
        y = y.reshape(1, y.size)

    # 教師データがone-hot-vectorの場合、正解ラベルのインデックスに変換
    if d.size == y.size:
        d = d.argmax(axis=1)

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

活性化関数

出力層と中間層との違い

  • 値の強弱

    • 中間層:閾値の前後で信号の強弱を調整
    • 出力層: 信号の大きさ(比率)はそのままに変換
  • 確率出力

    • 分類問題の場合は出力層の出力は0~1の範囲に限定し、総和を1にする

ソフトマックス関数

使い分け

# ソフトマックス関数
def softmax(x):
    if x.ndim == 2:
        x = x.T
        x = x - np.max(x, axis=0)
        y = np.exp(x) / np.sum(np.exp(x), axis=0)
        return y.T

    x = x - np.max(x) # オーバーフロー対策
    return np.exp(x) / np.sum(np.exp(x))

4. 勾配降下法

勾配降下法

$w^{(t+1)} = w^{(t)} - \epsilon \nabla E$

$\nabla E=\frac{\partial E}{\partial w} = [ \frac{ \partial E}{ \partial w_1}...\frac{ \partial E}{ \partial w_M}]$

学習率

学習が小さい場合発散することは無いが、小さすぎると収束するまでに時間がかかる

以下のようなアルゴリズムがある

  • Momentum
  • AdaGrda
  • Adadelta
  • Adam ←よく利用される

確率的勾配降下法

ランダムに抽出したサンプルの誤差を求める

$w^{(t+1)} = w^{(t)} - \epsilon \nabla E_n$

メリット

  • データが冗長な場合の計算コストの削減
  • 望まない局所極小解に収束するリスク削減
  • オンライン学習ができる

ミニバッチ勾配降下法

オンライン学習の考えを取り入れ、分割してバッチ学習を行う

$w^{(t+1)} = w^{(t)} - \epsilon \nabla E_n$

$E_t = \frac{1}{N_t} \sum_{n \in D_t}^{} E_n$

$N_t = |D_t|$

ランダムに分割したデータの集合(ミニバッチ) Dtに属するサンプルの平均誤差を求める

メリット

  • 確率的勾配降下法のメリットを損なわず、計算機の計算資源を有効活用できる
  • 並列での学習が可能

誤差勾配の計算

どう計算する?

$ \nabla E = \frac{\partial E}{\partial w} = [ \frac{\partial E}{\partial w_1} ... \frac{\partial E}{\partial w_M}]$

数値微分

プログラムで微小な数値を生成し、疑似的に微分を計算する一般的な手法

$\frac{\partial E }{\partial w_m} \approx \frac{E(w_m+h)-E(w_m -h)}{2h}$

5. 誤差逆伝播法

誤差逆伝播法

算出された誤差を、出力層側から順に微分し、前の層前の層へと伝播。最小限の計算で各パラメータの微分値を解析的に計算する手法

誤差関数: $ E(y) = \frac{1}{2} \sum_{j=1}^l(y_j-d_j)^2 = \frac{1}{2}||y-d||^2$

出力層の活性化関数: $y=u^{(t)}$

総入力の計算: $u^{(t)} = w^{(l)}z^{(l-1)}+b^{(l)}$

$\frac{\partial E}{\partial w_{ji}^{(2)}} = \frac{\partial E}{\partial y} \frac{\partial y}{\partial u} \frac{\partial u}{\partial w_{ji}^{(2)}} = (y_j-d_j)z_j$

$\frac{\partial E(y)}{\partial y} = \frac{\partial}{\partial y} \frac{1}{2} || y -d ||^2 = y-d $

$ \frac{\partial y(u)}{\partial u} = \frac{\partial u}{\partial u} = 1$

# 誤差逆伝播
def backward(x, d, z1, y):
    # print("\n##### 誤差逆伝播開始 #####")  

    grad = {}

    W1, W2 = network['W1'], network['W2']
    b1, b2 = network['b1'], network['b2']

    # 出力層でのデルタ
    delta2 = functions.d_mean_squared_error(d, y)
    # b2の勾配
    grad['b2'] = np.sum(delta2, axis=0)
    # W2の勾配
    grad['W2'] = np.dot(z1.T, delta2)
    # 中間層でのデルタ
    #delta1 = np.dot(delta2, W2.T) * functions.d_relu(z1)

    ## 試してみよう
    delta1 = np.dot(delta2, W2.T) * functions.d_sigmoid(z1)

    delta1 = delta1[np.newaxis, :]
    # b1の勾配
    grad['b1'] = np.sum(delta1, axis=0)
    x = x[np.newaxis, :]
    # W1の勾配
    grad['W1'] = np.dot(x.T, delta1)

    # print_vec("偏微分_重み1", grad["W1"])
    # print_vec("偏微分_重み2", grad["W2"])
    # print_vec("偏微分_バイアス1", grad["b1"])
    # print_vec("偏微分_バイアス2", grad["b2"])

    return grad

確認テスト

確認テスト1-1

Q. ディープラーニングはなにをしようとしているか。

A. プログラムの代わりにニューラルネットワークを利用し、入力値から目的値を求めるモデルを作成する

補足: 重み[w]やバイアス[b]を求める

確認テスト1-2

Q. 次のネットワークを紙にかけ

入力層: 2ノード1層

中間層: 3ノード2層

出力層: 1ノード1層

A.

確認テスト1-3

Q. この図式に動物分類の実例を入れてみよう

A.
x1: 体の大きさ

x2: 体の長さ

x3: 耳の大きさ

x4:しっぽの大きさ

確認テスト1-4

Q. この数式をPythonで書け

$ u = w_1x_1+w_2x_2+w_3x_3 = b$

A. u = np.dot(x, W) + b

確認テスト1-5

Q.1-1のファイルから中間層の出力を定義しているソースを抜き出せ

    # 2層の総入力
    u2 = np.dot(z1, W2) + b2

    # 2層の総出力
    z2 = functions.relu(u2)

補足: 中間層が今回は1つ

確認テスト2-1

Q.線形と非線形の違いを図にかいて簡易に説明せよ

左図 線形: 直線で表せることができるもの

右図 非線形: 表せないもの

[補足]

線形な関数は以下を満たす

  • 加法性: f(x+y) = f(x) + f(y)
  • 斉次性: f(kx) = kf(x)

確認テスト2-2

Q.
$z = f(u) ... (1.5)$

配布されたソースコードより該当する箇所を抜き出せ

# 1層の総出力
z1 = functions.relu(u1)

[補足]
from common import functionsという形でimportされているので関数自体は別ファイルに定義されている

def relu(x):
return np.maximum(0, x)

確認テスト3-1

$ En(w) = \frac{1}{2}\sum_{j=1}^l(y_j-d_j)^2 = \frac{1}{2}||(y-d)||^2$

Q.なぜ引き算ではなく二乗するのか

A.必ず正の値になるように調整するため

Q.1/2はどういう意味をもつのか

A.誤差逆伝搬の計算で微分を行う際に計算が簡単になる

補足:1/2に本質的な意味はない

確認テスト3-2

ソフトマックス関数の①~③に該当するソースコードを示し、説明せよ

def softmax(x):
    if x.ndim == 2:
        x = x.T
        x = x - np.max(x, axis=0)
        y = np.exp(x) / np.sum(np.exp(x), axis=0)
        return y.T

    x = x - np.max(x) # オーバーフロー対策
    return np.exp(x)② / np.sum(np.exp(x)③) ・・・①

9行目 return の箇所が実際の数式に該当する箇所である

補足: 3行目からの分岐はミニバッチで利用する処理

その他の処理はプログラムを安定させるための記述

確認テスト3-3

Q. ①~②の数式に該当するソースコードを示し、一行ずつ処理の説明をせよ。

def cross_entropy_error(d, y):
    if y.ndim == 1:
        d = d.reshape(1, d.size)
        y = y.reshape(1, y.size)

    # 教師データがone-hot-vectorの場合、正解ラベルのインデックスに変換
    if d.size == y.size:
        d = d.argmax(axis=1)

    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size), d] + 1e-7))(②) / batch_size ・・・①

A. 11行目 returnの文が該当

補足: 1e-7は対数関数を∞に飛ばした時、0になってしまうことを防ぐために利用している

確認テスト4-1

Q.オンライン学習とは何か

A.データをリアルタイムで読み取り、パラメータを更新する方法

補足: バッチ学習は一度にすべての学習データを使ってパラメータ更新を行う

確認テスト4-2

Q.この数式の意味を図に書いて説明せよ

$ w^ {(t+1)} = w^ {(t)} - \epsilon \nabla E_n$

A.
〇 -> 〇 -> 〇
t -> t+1 -> t+2
重みが $-\epsilon \nabla En $ずつ加えられていくイメージ

[参考]

確認テスト5-1

Q.誤差逆伝播法では不要な再帰的処理を割けることができる。既に行った計算結果を保持しているソースコードを抽出せよ

A.

# 出力層でのデルタ
delta2 = functions.d_mean_squared_error(d, y)