深層学習 Day 1 - Section 4 勾配降下法 のまとめ

この記事は個人的なお勉強用のメモです。

# このお勉強の位置

深層学習 Day 1

Section 0 ニューラルネットワークの全体像
Section 1 入力層～中間層
Section 2 活性化関数
Section 3 出力層
**Section 4 勾配降下法**　←　これ
Section 5 誤差逆伝播法

# 講義

- 勾配降下法
- 確率的勾配降下法
- ミニバッチ勾配降下法

## 勾配降下法

誤差 $E(w)$ を最小化するパラメータ $w$ を発見するための方法。

```math
w^{(t+1)}=w^{(t)}-\epsilon \nabla E\\
\nabla E = \frac{\partial E}{\partial w} = \Biggr[\frac{\partial E}{\partial w_1}...\frac{\partial E}{\partial w_M}\Biggl]
```

$w^{(t)}$：前回求めた重み（調整前の重み）
$\epsilon \nabla E$：調整する値
$\epsilon$：学習率
$w^{(t+1)}$：調整後の重み

$t$ の $+1$ というのは学習を繰り返すという意味。


## 学習率の特徴

学習率の大きさごとの欠点

学習率が大：最小値にたどり着かずに発散
学習率が小：収束までに時間がかかる、本当の最小値にたどり着かない場合がある（極小値に収束してしまう）

適切な学習率を設定する必要がある。

## 学習率のアルゴリズム

- Momentum
- AdaGrad
- Adadelta
- Adam　←　よく使われる

Day 2 で説明とのこと。

## 学習の流れ

1. 入力データをNNに与えて出力データを得る。
2. 出力データと正解値（訓練データ）を誤差関数に与えて誤差を計算する。
3. 誤差を元に重み $W$ とバイアス $b$ を更新する。

この1連の処理をエポックという。

動物の分類には、1つの動物あたり1,000～5,000枚くらいの入力画像が必要。

## 確率的勾配降下法（SGD）

ランダムに抽出したサンプルを使って学習する。
例：1,000枚の中から100枚を選んで学習、次に別の100枚を選んで学習。

メリット
- 学習コストを減らせる
- 極小解に収束しづらい
- オンライン学習できる

オンライン学習 <=> バッチ学習
バッチ学習とは、学習用データを先に全部揃えて学習すること。
オンライン学習とは、学習データを少しずつ（リアルタイムに）集めて学習すること。

現状はオンライン学習がよく使われる。
バッチ学習ではメモリ不足が起きやすいため。

## ミニバッチ勾配降下法

学習用データを分割して学習する方法。
この分割後のデータをミニバッチという。
バッチ学習とオンライン学習の中間のイメージ。

ディープラーニングでは当たり前のように使われている。

例
10万枚の画像を学習するときに、500枚ずつ小分けにして学習する。

注意
誤差を計算するときに、求めた誤差の総和をミニバッチの個数で割ること。

メリット

- ミニバッチに複数分割するため、CPUやGPUで並列化できる。  

## 誤差勾配の計算

```math
\nabla E = \frac{\partial E}{\partial w} = \Biggr[\frac{\partial E}{\partial w_1}...\frac{\partial E}{\partial w_M}\Biggl]
```

多くの重みを計算する方法。

### 数値微分

```math
\frac{\partial E}{\partial w_m}= \frac{E(w_m+h)-E(w_m-h)}{2h}
```

$h$：微小な値
$w_m$ の前後の微小な値の傾きを求める。

デメリット
計算量が多い。重みごとに何回も同じ計算をする必要がある。
このため、数値微分ではなく誤差逆伝播法を使うのが普通。
次の Section へ。

# 実装演習

1_3_stochastic_gradient_descent.ipynb

勾配降下法に該当するソースコードはこれ。

```python
# 勾配降下の繰り返し
for dataset in random_datasets:
    x, d = dataset['x'], dataset['d']
    z1, y = forward(network, x)
    grad = backward(x, d, z1, y)
    # パラメータに勾配適用
    for key in ('W1', 'W2', 'b1', 'b2'):
        network[key]  -= learning_rate * grad[key]

    # 誤差
    loss = functions.mean_squared_error(d, y)
    losses.append(loss)
```

backward関数の戻り値をgrad変数にセットする。
（backward関数については次のSectionで学習。）

grad変数には、W1,W2,b1,b2を更新するための傾きの値がディクショナリとして格納されている。
それぞれの値に learning_rateという学習率をかけて、元の値から引く。
これによって、誤差が小さくなるよう重みやバイアスを更新している。

# 確認テスト

### 重みを更新するソースコード

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810819/fa752733-0912-3d66-029f-15b6661e273d.png)

network[key]：重み
learning_rate：学習率
grand[key]：傾き

### オンライン学習とは

学習用のデータをすべて集めてから学習するのではなく
ある程度ずつ学習用のデータを集めて学習を進めていく方法。

模範解答
学習データが入ってくるたびに都度パラメータを更新し、学習を進めていく方法。
一方、バッチ学習では一度にすべての学習データを使ってパラメータ更新を行う。

少しずつ学習、ではなく、イメージ的にはリアルタイム的に、ということか。

### 重みを更新する様子を図にする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810819/8f52af3b-73f3-47bd-7e90-1d97da4e2df1.png)

上記のグラフを描いたが不正解。
正解はこちら。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810819/4e288aee-012f-4982-9d1f-9b586a33cf57.png)

正解を見れば理解はできるが、
この問題でこの解答を初見で出すのは難しい。


# 修了テスト～練習問題～

終了テストの中に勾配降下法の問題は見つからなかった。
代わりに赤本で勉強したこと。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810819/b6f1fe65-8091-8d0f-e764-64735f381296.png)

上記は数式が $x_1^2+x_2^2$ で学習率が 10.0 の動作結果。
講義では学習率が大きい場合に発散してしまう、という話があったが
実際に動かしてみたところ本当に発散した。