JDLA認定プログラム：深層学習（Day2）

本記事は、Study-AI社様のJDLA認定プログラムの提出レポートを兼ねた記事となっております。

##講義要約

###Sec1: 勾配消失問題
* シグモイド関数の微分値は最大でも0.25。故に何度もシグモイドで微分を行うと勾配消失が起きやすい。

```math
\begin{align}
f(u)' &= (1 - sigmoid(u)) * sigmoid(u)\\
&= (1 - 0.5) * 0.5
\end{align}
```

####勾配消失問題の解決法
* 活性化関数の選択
 + Relu関数：閾値を超えた値はそのままの値で伝わる関数。
* 重みの初期値設定
 + Xavierの初期値：重みの要素を、前の層の平方根で除算した値。

 ```python
 network["W1"] = np.random.randn(input_layer_size, hidden_layer_size) / np.sqrt(input_layer_size)
 network["W2"] = np.random.randn(hidden_layer_size, output_layer_size) / np.sqrt(hidden_layer_size)
 ```
 + Heの初期値：重みの要素を、前の層の平方根で除算した値に対し、$\sqrt 2$を掛け合わせた値

 ```python
 network["W1"] = np.random.randn(input_layer_size, hidden_layer_size) / np.sqrt(input_layer_size) * np.sqrt(2)
 network["W2"] = np.random.randn(hidden_layer_size, output_layer_size) / np.sqrt(hidden_layer_size) * np.sqrt(2)
 ```

* バッチ正規化
 + ミニバッチ単位で、入力値のデータの偏りを抑制する手法
 + 活性化関数に値を渡す前後に、バッチ正規化処理を含んだ層を加える。
 + バッチ正規化層への入力値は
 $$ u^{(l)} = w^{(l)}z{(l-1)} + b^{(l)}$$　または $$ z $$
     - $u^{(l)}$は入力値に重みが掛けられバイアスが加わった値
     - $z$は、$u^{(l)}$が活性化関数を通った後の値
 + バッチ正規化の数学的記述

$$
\begin{align}
&1. \mu_t = \frac{1}{N_t} \sum_{i=1}^{N_t} x_{n i} \\\
&2. \sigma_t^2 = \frac{1}{N_t} \sum_{i=1}^{N_t} (x_{n i} - \mu_t)^2 \\\
&3. \hat{x_{n i}} = \frac{x_{n i} - \mu_t}{\sqrt{\sigma_t^2 + \theta}} \\\
&4. y_{n i} = \gamma_{ni}^x + \beta \\\
\end{align}
$$

```math
\begin{align}
&\mu_t: ミニバッチt全体の平均 \\\
&\sigma_t^2: ミニバッチ全体の標準偏差\\\
&N_t: ミニバッチのインデックス\\\
&\hat{x_{n i}} : 0に近づける計算（0を中心とするセンタリング）と正規化を施した値\\\
&\gamma : スケーリングパラメータ\\\
&\beta: シフトパラメータ\\\
&y_{n i}: ミニバッチのインデックス値とスケーリングの積にシフトを加算した値（バッチ正規化オペレーションの出力）
\end{align}
```


###Sec2: 学習率最適化手法
* 深層学習の目的は誤差を最小化するパラメータ$w$を発見すること。<br>→勾配降下法を利用してパラメータを最適化
$$ w^{(t+1)} = w^{(t)} - \epsilon \nabla E $$
* 勾配降下法の学習率は手動で設定する他に、学習率最適化手法がある。

####モメンタム
$$ V_t = \mu V_{(t-1)} - \epsilon \nabla E $$

```python
self.v[key] = self.momentum * self.v[key] - self.learning_rate * grad[key]
```

$$ w^{(t+1)} = w^{(t)} + V_t $$

```python
params[key] += self.v[key]
```

$$慣性：\mu $$
* 誤差をパラメータで微分したものと学習率の積を減算した後、現在の重みに前回の重みを減算した値と慣性の積を加算する。
* 慣性の値：0.5~0.9程度か
* モメンタムのメリット：
  + 局所的最適化にならず大域的最適解となる。
  + 谷間に着いてから最も低い位置（最適値）に行くまでの時間が早い。

####AdaGrad
* 誤差をパラメータで微分したものと再定義した学習率の積を減算する
* 初期値に$\theta$(＝極小の値)を与える
$$ h_0 = \theta $$

```python
self.h[key] = np.zeros_like(val)
```

* 誤差を二乗して加算していく
$$ h_t = h_{t-1} + (\nabla E)^2 $$

```python
self.h[key] += grad[key] * grad[key]
```

* $\theta$(コードでは1e-7)は分母が０にならないために与える
$$ w^{(t+1)} = w^{(t)} - \epsilon \frac{1}{\sqrt{h_t} + \theta} \nabla E $$

```python
params[key] -= self.learning_rate * grad[key] / (np.sqrt(self.h[key]) + 1e-7)
```

* AdaGradのメリット：
 + 勾配の緩やかな斜面に対して、最適値に近づける
* 課題：
 + 学習率が徐々に小さくなるので、鞍点問題（極小値でなく極大値に陥る）を引き起こすことがあった。

####RMSProp
* 誤差をパラメータで微分したものと再定義した学習率の積を減算する。
$$ h_t = ah_{t-1} + (1-a)(\nabla E)^2 $$

```python
self.h[key] *= self.decay_rate
```

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

```python
params[key] -= self.learning_rate * grad[key] / (np.sqrt(h[key]) + 1e-7)
```

* RMSPropのメリット：
 + 局所最適解にはならず、大域的最適解となる。（AdaGradの解決策として）
 + ハイパーパラメータの調整が必要な場合が少ない。

####Adam
* モメンタムの、過去の勾配の指数関数的減衰平均
* RMSPropの、過去の勾配の２乗の指数関数的減衰平均
* 上記をそれぞれ孕んだ最適化アルゴリズムである。


###Sec3: 過学習
* 過学習：テスト誤差と訓練誤差とで学習曲線が乖離すること。
* 原因： ネットワークの自由度が高い
 + パラメータの数が多い
 + パラメータの値が適切でない
 + ノードが多過ぎる など
* 正則化：ネットワークの自由度（層数、ノード数、パラメータの値など）を制約すること
* 荷重減衰（Weight decay）
 + 過学習の原因：重みが大きい値をとることで発生
    - 学習の過程で重みにばらつきが発生する。重みが大きい値は、学習において重要な値であり、重みが大きいと過学習が起こる。
 + 過学習の解決策：誤差に対し正則化項を加算し重みを抑制する
    - 過学習が起こりそうな重みの大きさ以下で重みをコントロールし、かつ重みの大きさにバラつきを出す必要がある。 

####L1正則化、L2正則化
* 誤差関数にpノルムを加える
$$ E_n(W) + \frac{1}{p} \lambda \begin{Vmatrix} x \end{Vmatrix}_p $$

```python
weight_decay += weight_decay_lambda * np.sum(np.abs(network.params['W' + str(idx)]))
loss = network.loss(x_batch, d_batch) + weight_decay
```

* pノルムの計算
$$ \begin{Vmatrix} x \end{Vmatrix}\_p = (\begin{vmatrix} x_1 \end{vmatrix}^p + \cdots + \begin{vmatrix} x_n \end{vmatrix}^p)^{\frac{1}{p}} $$

```python
np.sum{np.abs(network.params['W' + str(idx)])}
```

* p = 1の場合、L1正則化と呼ぶ。
 + 0の値をとる事ができる→スパース化の問題に対応できる。
* p = 2の場合、L2正則化と呼ぶ。
 + 精度向上の面では積極的に採用すべきか。

####ドロップアウト
* ランダムにノードを削除して学習させることで、ノード数が多い問題に対処。
* 各層ないし各ノードに閾値を設けて、閾値を超えないノードを不活性化させる。
* メリット：データ量を変化させずに、異なるモデルを学習させていると解釈できる。


###Sec4: 畳み込みニューラルネットワーク
* LeNet：CNNの基本型
* 入力値 * フィルター(全結合でいう重み) → 出力値 + バイアス → 活性化関数$f(x)$ → 出力値

####畳み込み層
* 三次元の空間情報も学習できるような層が畳み込み層である。
 + バイアス：フィルターを掛けた値に加算する。
 + パディング： 入力データ周縁に値を与え入出力データのサイズを合わせる、基本はゼロパディング。
 + ストライド：フィルターをズラす幅。
 + チャンネル：入力データを分解した層数・奥行き。チャンネル数はフィルターも合わせる。
* 全結合層では画像も１次元データとして処理されチャンネル間の関係性が学習されなかったが、畳み込み層ではチャンネル間の関係性が学習され３次元データに対応できるようになった。
* im2col(image to column)
 + 画像のような多次元データを２次元配列にする。 
 + メリット：行列計算に落とし込むことで、多くのライブラリを活用できるようになる。
* col2im(column to image)
 + im2colとは全く別のアルゴリズムを使っているので、im2colの出力をcol2imで復元しようとしても整合性が取れない。


####プーリング層
* 入力画像の対象領域のMax値または平均値を取得し、出力として採用する。
 + それぞれ MaxPooling、Average Pooling という。

###Sec5: 最新のCNN

####AlexNet
* ５層の畳み込み層およびプーリング層など、それに続く３層の全結合層から構成される。
* ポイント：過学習を防ぐ施策
 + サイズ4096の全結合層の出力にドロップアウトを使用している。


##確認テストと考察

###Sec0.
* 連鎖律の原理を使い、dz/dxを求めよ。
$$z = t^2$$
$$t = x+y$$

```math
\begin{align}
\frac{dz}{dx} &= \frac{dz}{dt}\frac{dt}{dx} \\\
&= 2t * 1\\\
&= 2t\\\
&= 2(x + y)
\end{align}
```

* シグモイド関数を微分したとき、入力値が0のときに最大値を取る。その値として正しいものを選択肢から選べ。

```math
\begin{align}
f(u)' &= (1 - sigmoid(u)) * sigmoid(u)\\\
&= (1 - 0.5) * 0.5
\end{align}\\\
\\\
(2)0.25
```

###Sec1.
* 重みの初期値に0を設定すると、どのような問題が発生するか。簡潔に説明せよ。

```
計算結果が０になり誤差が伝わらずパラメータチューニングが行われない。
```

* 一般的に考えられるバッチ正規化の効果を２つ挙げよ。

```
・勾配消失問題が起きづらくなる
・ニューラルネットが学習しやすくなり計算精度や速度があがる
```

###Sec2.
* モメンタム・AdaGrad・RMSPropの特徴をそれぞれ簡潔に説明せよ。

```
・モメンタム：谷間に落ちてから収束するまでが早い
・AdaGrad： 緩やかな斜面に対しても対応できる
・RMSProp： パラメータの調整が少ない
```

###Sec3.
* 機械学習で使われる線形モデルの正則化は、モデルの重みを制限することで可能となる。前述の線形モデルの正則化手法の中にリッジ回帰という手法があり、その特徴として正しいものを選択しなさい。

```
(a) ハイパーパラメータを大きな値に設定すると、全ての重みが限りなく０に近づく
```

* L１正則化を表しているのはどちらか答えよ。

```
右図
（Lasso推定量/スパース推定）
```
* 5. L2パラメータ正則化

```
(4) param
```

* 6. L1パラメータ正則化

```
(3) np.sign(param)
※符号関数：正の数は１、0は0、負の数は-1で返す関数。故に絶対値の微分
```

* 7. データ集合の拡張

```
(4) image [ top:bottom, left:right, : ] 
```

###Sec4.
* サイズ６×６の入力画像を、サイズ２×２のフィルタで畳み込んだときの出力画像のサイズを答えよ。ストライドとパディングは１とする。

```
7×7
```

##演習結果と考察

###2_2_1_vanishing_gradient
* 演習結果<br>
http://foraistudy.s3-website-ap-northeast-1.amazonaws.com/

* 考察
 + 活性化関数をシグモイド関数からReLU関数に変えることで精度が向上し勾配消失問題が解消されたことが確認出来た。
 + 初期値設定を行うことで収束速度が劇的に向上することが確認出来た。

###2_2_2_vanishing_gradient_modified
* 演習結果<br>
http://222vgm.s3-website-ap-northeast-1.amazonaws.com

* 考察
 + 隠れ層のノード数を増やすことで多少の精度向上が見て取れたが、計算に掛かる時間は目に見えて増加した。
 + ２種類の初期値についてはどちらかが常に精度・速度について優れているというわけではなく、組み合わせ次第で変化し得ることが見て取れた。

###2_4_optimizer
* 演習結果<br>
https://24optimizer.s3-ap-northeast-1.amazonaws.com/2_4_optimizer_2.html

* 考察
 + momentumの値を0.9→0.5に変更したところ、収束速度が著しく低下した。
 + バッチ正規化がいかに効果的かが確認できた。
 + AdaGradの学習率を0.1から上げても大きな変化は見られないが、下げると収束速度が目に見えて低下した。
 + RMSPropのdecay_rateは0.99など極大値や0.01など極小値では収束が遅れる傾向にあるように見えたが、どの値が適切であるかは判断が難しく多くの試行を要した。

###2_5_overfiting
* 演習結果<br>
https://25overfiting.s3-ap-northeast-1.amazonaws.com/2_5_overfiting.html

* 考察
+ 正則化強度については何度か試行をして微調整する必要があると思った。
+ L1正則化に関して、学習精度にムラがあり実用性については疑問符が付くと感じた。
+ dropputを組みわせることで、L1における学習曲線のムラが抑制された。

###2_6_simple_convolution_network
* 演習結果<br>
https://26scn.s3-ap-northeast-1.amazonaws.com/2_6_simple_convolution_network_2.html

* 考察
 + im2colの出力をcol2imに通しても完全に元データを復元することはできないことが確認できた。