【ラビットチャレンジ】 深層学習（前編・day2）

##連鎖率
###確認テスト
![Image-1-3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375106/94a08ea2-3bef-9280-9c53-d6ef3f600151.jpeg)


# Section1：勾配消失問題
## 活性化関数
- シグモイド関数は0~1の間を緩やか変化する．
    - 大きな値では出力の変化が微小なため，勾配消失問題を引き起こす．
    - 更に，逆伝播の各層でシグモイド関数の微分を掛けていくと，逆伝播誤差が減少していく．
        - （$\frac{df}{du}$の最大値は，入力値 $u=0$ のときの $0.25$ ．）

### 確認テスト
![Image-1-4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375106/b8f00bae-63a8-601a-3d60-491efa206746.jpeg)


$$ f(u) = \frac{1}{1+e^{-u}}$$$$ \frac{df}{du} = \frac{e^{-u}}{(1+e^{-u})^2}=f(u)(1-f(u))$$

- 活性化関数としてReLUを用いることで勾配消失の回避やスパース化に効果がある．


## 重みの初期値設定
- Xavier
    - 活性化関数：ReLU関数，シグモイド関数，$\tanh$
- 初期値の設定方法：重みの要素を前の層のノード数の平方根で除算した値．

```python:python
# Xavierの初期値
    network['W1'] = np.random.randn(input_layer_size, hidden_layer_1_size) / (np.sqrt(input_layer_size))
    network['W2'] = np.random.randn(hidden_layer_1_size, hidden_layer_2_size) / (np.sqrt(hidden_layer_1_size))
    network['W3'] = np.random.randn(hidden_layer_2_size, output_layer_size) / (np.sqrt(hidden_layer_2_size))
```

- He
    - 活性化関数：ReLU関数
- 初期値の設定方法：重みの要素を前の層のノード数の平方根で除算した値に対して$\sqrt{2}$ をかけ合わせた値．

```python:python
# Heの初期値
    network['W1'] = np.random.randn(input_layer_size, hidden_layer_1_size) / np.sqrt(input_layer_size) * np.sqrt(2)
    network['W2'] = np.random.randn(hidden_layer_1_size, hidden_layer_2_size) / np.sqrt(hidden_layer_1_size) * np.sqrt(2)
    network['W3'] = np.random.randn(hidden_layer_2_size, output_layer_size) / np.sqrt(hidden_layer_2_size) * np.sqrt(2)
 
```

###確認テスト
重みの初期値に$0$を設定すると，どのような入力に対しても同じ値が出力されるため，それ以上学習（重みのチューニング）が進まない．

## バッチ正規化
- ミニバッチ単位で，入力値のデータの偏りを抑制する．
- 活性化関数に値を渡す前後に，バッチ正規化の処理を孕んだ層を加える．

### 確認テスト
- バッチ正規化の効果（２点）
    - 計算量の高速化
    - 勾配消失が起こりにくくなる

数式などはスライドを参照する．


# Section2：学習率最適化手法

- 勾配降下法の復習
$$\boldsymbol w^{(t+1)} = \boldsymbol w^{(t)}-\epsilon \nabla E$$
$\epsilon$：学習率 を最適化したい．

### 学習率の決め方とは（方針）
- 初期の学習率を大きく設定し，徐々に学習率を小さくしていく．
- パラメータごとに学習率を可変させる．

→学習率最適化手法を利用して（自動で）学習率を最適化する．

## モメンタム
- 誤差をおパラメータで微分したものを学習率の積を減算した後，現在の重みに前回の重みを減算した値と慣性（$\mu$． 0.05-0.09くらい）の積を加算する．
$$V_t = \mu V_{t-1} -\epsilon \nabla E$$

```python:python
    self.v[key] = self.momentum * self.v[key] - self.learning_rate * grad[key]    
```
$$\boldsymbol w^{(t+1)} = \boldsymbol w^{(t)}+V_t$$

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

###確認テスト
- モメンタムのメリット
    - 局所最適解にはならず，大域的最適解となる．
    - 谷間についてから最も低い位置（最適値）にいくまでの時間が早い．


## AdaGrad
- 誤差をパラメータで微分したものと（実装上は意識する必要はないのだが）再定義した学習率の積を減算する．
$$h_0=\theta$$

```python:python
    self.h[key] = np.zero_like(val)
```
$$h_t = h_{t-1}+(\nabla E)^2$$

```python:python
    self.h[key] += grad[key] * grad[key]
```
$$\boldsymbol w^{(t+1)} = \boldsymbol w^{(t)} - \epsilon \frac{1}{\sqrt{h_t}+\theta} \nabla E$$

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

###確認テスト
- AdaGradのメリット
    - 勾配の緩やかな斜面に対して最適値に近づける．
- AdaGradの課題
    - 学習率が徐々に小さくなるので，鞍点問題を引き起こすことがあった．

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

```python:python
    self.h[key] *= self.decay_rate
    self.h[key] += (1-self.decay_rate) * grad[key] * grad[key]
```
$$\boldsymbol w^{(t+1)} = \boldsymbol w^{(t)} - \epsilon \frac{1}{\sqrt{h_t}+\theta} \nabla E$$

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

###確認テスト
- RMSPropのメリット
    - (AdaGradと比較して)局所的最適解にはならず，大域的最適解となる．
    - ハイパーパラメータの調整が必要な場合が少ない．

## Adam
- Adamとは，モメンタムとRMSPropの良いとこ取り．
    - モメンタムの，過去の勾配の指数関数的減衰平均
    - RMSPropの，過去の勾配の２乗の指数関数的減衰平均
<p>
をそれぞれ孕んだ最適化アルゴリズムである．

# Section3：過学習
- テスト誤差と訓練誤差とで学習曲線が乖離すること
    - 学習曲線を可視化することが重要
- 原因 → ネットワークの自由度が高い
    - パラメータの数が多い．
    - パラメータの値が適切でない．
    - ノードが多いetc...
   
## 正則化
- ネットワークの自由度を制約すること．過学習を抑制する．
- 正則化手法について
    - L1正則化，L2正則化
    - ドロップアウト

### Weight decay（荷重減衰）
- 過学習の原因
    - 重みが大きい値を取ることで，過学習が発生することがある．
        - 学習させていくと，重みにばらつきが発生する．重みが大きい値は，学習において重要な値であり重みが大きいと過学習が起こる．
- 過学習の解決策
    - 誤差に対して，正則化項を加算することで，重みを抑制する．
        - 過学習が起こりそうな重みの大きさ以下で重みをコントロールし，かつ重みの大きさにばらつきを出す必要がある．

### L1,L2正則化
- 誤差関数に，$p$ノルムを加える．
$$E_n(\boldsymbol w)+\frac{1}{p}||x||_p$$

### 確認テスト
リッジ回帰の特徴として正しいものはどれか？
→ ハイパーパラメータに大きな値を設定すると，すべての重みが限りなく0に近づく．

- $p$ノルムの計算
$$||x||_p=(|x_1|^p+\cdots+|x_n|^p)^ \frac{1}{p}$$

$p=1$の場合，L1正則化と呼ぶ．
$p=2$の場合，L2正則化と呼ぶ．
    実務では，$p=3$以上も使う場合がある

### 確認テスト
L1はLasso推定．スパース推定されるため，計算量が改善する．
L2は計算は多くなるが，最適化としては良い結果が出る．
使い分けが重要．

#### 正則化の計算
$$||\boldsymbol W ^{(1)}||_p = (|W_1^{(1)}|^p+\cdots+|W_n^{(1)}|^p)^{\frac{1}{p}} $$

$$||\boldsymbol W ^{(2)}||_p = (|W_1^{(2)}|^p+\cdots+|W_n^{(2)}|^p)^{\frac{1}{p}} $$

$$ ||x||\_p=||\boldsymbol W ^{(1)}||\_p + ||\boldsymbol W ^{(2)}||_p$$

```python:python
    np.sum(np.abs(network.params['W' + str(idx)]))
```
$$E_n(\boldsymbol w)+\frac{1}{p}\lambda||x||_p$$

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

    loss = network.loss(x_batch, d_batch) + weight_decay
```

## ドロップアウト
- 正則化で最も使われている手法
- ノード数が多い場合に過学習が発生しやすい．
    - ランダムにノードを削除して学習させる．
- データ量を変化させずに，異なるモデルを学習させていると解釈できる．

層に対して閾値を掛けているのか
ノードに対して閾値を掛けているのか = Chainer?


Dropout + L1 で，過学習の抑制と精度の向上が両立できている．
学習に時間がかかるので，理論を理解して仮説を立ててからそれぞれの手法を組み合わせることが重要．


# Section4：畳み込みニューラルネットワークの概念

###CNNとは
- 画像の分野で非常によく使われている．
    - 入力の加工によっては，音声などの時系列データに対しても適用できる．
- 複数の畳み込み層とプーリング層で構成される．
- LeNet：CNNの大元

##畳み込み層
### 全体像
入力値にフィルター（全結合でいう重み）を掛けて，出力値を得る．それにバイアスを足して活性化関数を通す．

- 畳み込み層では，画像の場合，縦，横，チャンネルの３次元のデータをそのまま学習し，次に伝えることができる．３次元の空間情報も学習できるような層が，畳み込み層である．（例えば，フィルタに通すことで色空間が表現できる．）

### パディング
入力画像の外側に架空の入力値を追加することで，入力画像のサイズを調整する．
ゼロパディングするのが一般的．

### ストライド
フィルタのずらし方
8x8，パディング1の入力画像に対して，3x3のフィルタをストライド2で作用させると3x3の出力画像が得られる．
6x6，パディング1の入力画像に対して2x2のフィルタをストライド1で作用させると7x7の出力画像が得られる．(確認テスト)

### チャンネル
入力画像を複数の空間に分ける（RGBなど）．分解した総数をチャンネル数という．
それぞれに対してフィルターを用意する．
（全結合層で処理すると，縦，横，チャンネルの３次元データが１次元データとして処理されるので，RGBの各チャンネルの関連性が学習に反映されない．）

### 実装
- im2colで画像データ（多次元配列）を２次元に落としこむ．行列計算に落とし込むことで，多くのライブラリを活用できる．
- col2imでim2colで変換した２次元配列を画像データに変換できる．
    - 全く同じものが出てくるわけではない．

##プーリング層
- マックスプーリング：畳み込み層の出力に対してあるサイズの領域を取り出し，その最大値を出力値とする．

- アベレージプーリング：畳み込み層の出力に対してあるサイズの領域を取り出し，その平均値を出力値とする．

# Section5：最新のCNN
- AlexNet
    - 2012年の画像認識コンペティションで２位に大差をつけて優勝，ディープラーニングが大きく注目を集めた．
    - ５層の畳み込み層およびプーリング層などそれに続く３層の全結合相から構成される．
    - 過学習を防ぐ施策として，サイズ4096の全結合相の出力にドロップアウトを使用している．


<br>
<br> 

[DeepLearning ラビットチャレンジ](http://ai999.careers/rabbit/　"ラビットチャレンジリンク")
<img src="http://ai999.careers/tools/wp/wp-content/uploads/2018/12/card.png" width=50%>