ラビットチャレンジ stage3 深層学習（前編） -day1-

#1.ニューラルネットワークの全体像
<dt>1-1.ニューラルネットワークの全体像</dt>

![スクリーンショット 2021-07-12 17.24.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221503/91e6a40f-180e-9998-6a66-49b9290380ea.png)


　　[確認テスト]
　　　　ディープラーニングは、結局何をやろうとしているか2行以内で述べよ。
　　　　また、次の中のどの値の最適化が最終目的か。全て選べ。

　　　　選択肢
　　　　①入力値[X]　　②出力値[Y]　　③重み[W]　　④バイアス[b]　　⑤総入力[u]
　　　　⑥中間層入力[z]　　⑦学習率[p]


　　　[回答]
　　　明示的なプログラムの代わりに多数の中間層を持つニューラルネットワークを用いて、
　　　入力値から目的とする出力値に変換する数学モデルを構築すること
　　　　選択肢：③、④


![スクリーンショット 2021-07-12 20.15.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221503/1fe56046-68e7-4701-c318-974d697a0df4.png)


　　○詳しく見ていくと、xという値を受け取り、yという値を出力していく。
　　　　重要なのは、入力層⇨中間層⇨出力層にかけて、必ず何かしらの入力と出力がある変換機である。

　　○yの出力ができたら、d（正解ラベル）と比較を行い、誤差を求める。
　　　　誤差を元に、パラメータw、bを更新し、より分類できるように学習していく。

　　[確認テスト]
　　　　次のネットワークをかけ。
　　　　　　入力層：２ノード１層
　　　　　　中間層：３ノード２層
　　　　　　出力層：１ノード１層

![スクリーンショット 2021-07-12 20.32.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221503/6716795d-f39b-51bd-abab-3d19f0c34d09.png)

<dt>1-2.ニューラルネットワークでできること</dt>
　●回帰
　　○結果予測
　　　■売り上げ予想
　　　■株価予想
　　○ランキング
　　　■競馬順位予想
　　　■人気順位予想

 ○連続する実数値をとる関数の近似

　　【主な手法】
　　　・線形回帰
　　　・回帰木
　　　・ランダムフォレスト
　　　・**ニューラルネットワーク（NN）**


　●分類
　　　■猫写真の判別
　　　■手書き文字認識
　　　■花の種類分類

　　○性別（男あるいは女）や動物の種類など離散的な結果を予想するための分析

　【主な手法】
　　・ベイズ分類
　　・ロジスティック回帰
　　・決定木
　　・ランダムフォレスト
　　・**ニューラルネットワーク(NN)**


　●深層学習の実用例
　　・自動売買（トレード）
　　・チャットボット
　　・翻訳
　　・音声解釈
　　・囲碁、将棋AI

#2.入力層〜中間層

<dt>2-1.入力層から中間層</dt>
 
![スクリーンショット 2021-07-12 20.52.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221503/969d3257-4884-7799-7a82-36ebec786bdc.png)


　　●x（入力）の値をw（重み）で掛けた値　＋　b（バイアス）を全て足すことで、uを求めることができる。
　　　○xに掛けられるwはグラフで表すときの傾き度合いを制御する。

　　　　　そのため、各xの値がどれほど重要なのかがwによって決まる。
　　　○bはグラフで表すときの切片を制御する。
　　　　　切片を制御することによって、直線の位置をずらすことができる。


![スクリーンショット 2021-07-12 21.07.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221503/6f5ce474-3310-1a2e-d0b6-64e73ea4da6b.png)


　　[確認テスト1]
　　上の図式に動物分類の実例を入れる。

![スクリーンショット 2021-07-12 21.20.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221503/aae4741a-d709-5210-3e76-00db09aac264.png)


　　[確認テスト２]
　　上図にある、計算式をpythonでかけ
 
```math
 \begin{eqnarray}
  u &=& w_1 x_1 + w_2 x_2 + w_3 x_3 + w_4 x_4 + b \\
    &=& \boldsymbol{W} \boldsymbol{x} + b
 \end{eqnarray}
 ```

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

　

![スクリーンショット 2021-07-12 21.34.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221503/10d77e78-246b-9384-fadf-863b1e14fef9.png)

　　[確認テスト3]
　　上図の中間層を定義している、ソースを抜き出せ

 ```python
  # 2層の総入力
    u2 = np.dot(z1, W2) + b2
    
  # 2層の総出力
    z2 = functions.relu(u2)
 ```

　
<dt>2-2.活性化関数</dt>
　
　●ニューラルネットワークにおいて、次の層への出力の大きさを決める**非線形の関数**
　●入力値の値によって、次の層への信号のON/OFFや強弱を定める働きをもつ
　
　　[確認テスト]
　　　線形の図と、非線形の図を描き、簡単に説明せよ

![スクリーンショット 2021-07-12 21.55.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221503/1a4a616b-234d-328e-5f56-a2a88671d872.png)


　　○線形な関数：y=axのように直線で表されるような関数
　　○非線形な関数：直線で表せず、曲線で表されるような関数

　●活性化関数は先程の、u=Wx+bで求めた、uの値を入力とする。
　　　Wやxでは線形な関数になるが、活性化関数を通すことによって、非線形な関数となり、
　　　様々なバリエーションを作成できることが、重要である。

　
<dt>2-3.中間層の活性化関数</dt>　
●ステップ関数
　　○現在ではあまり使用されていない関数
　　○閾値を超えたら、発火する関数であり、出力は常に１か０となる。
　　○パーセプトロン（ニューラルネットワークの前身）で利用された関数。
　　　■課題：０-1の間を表現できず、線形分離可能なものしか学習できなかった。
　
　　・数式

  ```math
   f(x) =
   \left\{
   \begin{array}{ll}
    1 & (x \geqq 0) \\
    0 & (x  < 0 ) 
   \end{array}
   \right.
  ```
  
　　・サンプルコード

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

 ・グラフ

![step関数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221503/5dc2e587-a154-85d5-fe62-c39e70e524ef.png)


　
　●シグモイド関数
　　○０〜１の間に緩やかに変化する関数で、ステップ関数ではON/OFFしかない状態に対し、
　　　信号の強弱をつけられるようになり、予想ニューラルネットワークの普及のきっかけとなった。
　　　■課題：大きな値では出力の変化が微小なため、**勾配消失問題**を引き起こすことがあった。

　　　・数式

  ```math
   f(u) = \frac{1}{1 + e^{-u}}
  ``` 

　　　・サンプルコード
  
  ```python
   def sigmoid(x):
     return 1 / (1 + np.exp(-x)))
  ``` 
 
　　　・グラフ

![sigmoid関数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221503/03c270ea-55bf-ffc9-2369-b52021ce98ef.png)


　●RELU関数
　　○今最も使われている活性化関数
　　○**勾配消失問題**の回避と**スパース化**に貢献することで、良い成果をもたらしている。

　　・数式

  ```math
   f(x) = 
   \left\{
   \begin{array}{ll}
     x & (x > 0) \\
     0 & (x \leqq 0)
   \end{array}
   \right.
  ``` 

　　　・サンプルコード
  
  ```python
   def relu(x):
      return np.maximum(0,x)
   ```

　　　・グラフ

![RELU関数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221503/628cf0f2-565c-3668-3b64-18df21a53e56.png)


　　[確認テスト]
　　　配布されたソースコードより、z=f(u)に該当する箇所を抜きだせ

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

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

#3.出力層

<dt>3-1.出力層の役割</dt>
　
　●出力層は人間の欲しいデータを最終的に出す場所
　　　（各クラスごとの確率など）
　
　●出力層で結果を出力できた後は、訓練データ（正解値）と比較を行い、
　　　どれほどの誤差が出たかを確認する。
　　　○イメージ：問題集で問題を解いてみて、回答と比較する。
　
　●誤差を求めるには、**誤差関数**を使用する。
　　例）二乗誤差

  ```math
   E_n(W) = \frac{1}{2} \sum_{j=1}^{J} (y_j - d_j)^2 = \frac{1}{2} 
   || y - d||^2
  ```


　　[確認テスト]
　　　・二乗誤差ではなぜ引き算ではなく二乗するかを述べよ
　　　　　
　　　　　　引き算を行なってしまうと、誤差に負の値が出てきてしまう可能性があり、
　　　　　　誤差を求める上で、都合が悪いため

　　　・1/2はどういう意味を持つか述べよ

　　　　　　後に微分を求める際に$ ||y - d||^2 $ の二乗と打ち消しあうため

<dt>3-2.出力層の活性化関数</dt>
　
　●中間層と出力層の違い
　　【値の強弱】
　　　・中間層：閾値の前後で信号の強弱を調整
　　　・出力層：信号の大きさ（比率）をそのままに変換
　
　　【確率出力】
 　・分類問題の場合、出力層の出力は０〜１の範囲に限定し、総和を1にする必要がある。

　　⇨中間層と出力層では利用される活性化関数が異なってくる。


<table>
 <tr>
  <td></td>
  <td>回帰</td>
  <td>ニ値分類</td>
  <td>多クラス分類</td>
 </tr>
 <tr>
  <td>活性化関数</td>
  <td>恒等写像</td>
  <td>シグモイド関数</td>
  <td>ソフトマックス関数</td>
 </tr>
 <tr>
  <td>誤差関数</td>
  <td>二乗誤差</td>
  <td colspan="2" align="center">交差エントロピー</td>
　</tr>
</table>

　●活性化関数

　　○シグモイド関数

　　・数式

  ```math
   f(u) = \frac{1}{1 + exp^{(-u)}}
  ```

　　・サンプルコード

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

　
　　○ソフトマックス関数

　　　・数式

  ```math
   f(i, u) = \frac{e^{u_i}}{\sum_{k=1}^{K} e^{u_k}}
  ```

　　　・サンプルコード

 ```python
  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))
  ```

　　[確認テスト]
  ソフトマックス関数のソースコードを配布データから抜き出し、1行ずつ説明せよ。

 ```python
  # ソフトマックス関数
  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))
 ```

　●誤差関数

　　○二乗誤差

　　　・数式

  ```math
   E_n(W) = \frac{1}{2} \sum_{j=1}^{J} (y_j - d_j)^2 = \frac{1}{2} 
   || y - d||^2
  ```

　　　・サンプルコード
 
  ```python
   #平均二乗誤差
   def mean_squared_error(d, y):
     return np.mean(np.squared(d - y)) / 2
  ```

　
　　○交差エントロピー

　　・数式

 ```math
   E_n(W) = - \sum_{i=1}^{I} d_i \  log \  y_i
 ```

　　　・サンプルコード

  ```python
   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
  ```

　　　[確認テスト]
  交差エントロピーのソースコードを配布データから抜き出し、1行ずつ説明せよ。

  ```python
   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]

    #本質的な計算は以下の文
    #1e-7は対数関数で、０の時ー∞に飛ぶため、０に落ちないように掛けてある
    #yは０か１が並んでいる
    #dはニューラルネットワークが正解と選んだ場所
    return -np.sum(np.log(y[np.arange(batch_size), d] + 1e-7)) / batch_size
  ```

#4 勾配降下法

<dt>4-1.勾配降下法</dt>
　
　●ニューラルネットワークを学習させるための手法
　　○深層学習の目的：学習を通して誤差を最小にするネットワークを作成すること
　　　　⇨誤差E(w)を最小とするようなパラメータwを発見すること
　　　　　　⇨勾配降下法を利用して、パラメータを最適化

　　・数式
  $$ w^{(t+1)} = w^{(t)} - \varepsilon \nabla E $$

　　[確認テスト]
　　　上の数式に該当するソースコードを探せ

  ```python
   network[key]  -= learning_rate * grad[key]
  ```

  ```python
    grad = backward(x, d, z1, y)
  ```

　
　●学習率の値によって学習の効率が大きく異なる
　
　　○学習率が大きすぎた場合、最小値にいつまでもたどり着かず発散してしまう。
　
　　○学習率が小さい場合発散することはないが、小さすぎると収束するまでに時間がかかってしまう。
　
　●勾配降下法の学習率の決定、収束性向上のためのアルゴリズムについては様々な手法がある。
　　・Momentum
　　・AdaGrad
　　・Adadelta
　　・Adam

　●全体を通してみると
　　　入力層から中間層を経て、出力層に値が出力され、
　　　出力値と訓練データの誤差を誤差関数を使用して、学習しパラメータを更新していく
　　　この１連の流れを何回も行い、誤差を小さくしていく。
　　　１連の流れのことをエポックと呼ぶ。
　
<dt>4-2.確率的勾配降下法</dt>
　●勾配降下法は全サンプルの平均誤差を使用するのに対し、
　　　確率的勾配降下法はランダムに抽出したサンプルの誤差を使用して、学習を行う

　●メリット
　　○データが冗長な場合の計算コストを軽減
　　○望まない局所極小解に収束するリスクを軽減
　　○オンライン学習ができる
　　　オンライン学習とは徐々に集まってくるデータに対し、学習を行うことができる。
　　　反対に、あらかじめ全ての学習データを準備することをバッチ学習という。

　　[確認テスト]
　　　オンライン学習とは何か2行で説明せよ

　　　　オンライン学習とは徐々に集まってくるデータに対し、学習を行うことができる。
　　　　反対に、あらかじめ全ての学習データを準備することをバッチ学習という。

<dt>4-3.ミニバッチ勾配降下法</dt>

　●ミニバッチ勾配降下法は、ランダムに分割した、データの集合（ミニバッチ）
　　　$D_t$に属するサンプルの平均誤差を利用し、学習を行う。

　●メリット
　　　○確率的勾配降下法のメリットを損なわず、計算機の計算資源を有効利用できる
　　　　⇨CPUを利用したスレッド並列化やGPUを利用した、SIMD並列化

 　・数式

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

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

   $$ N_t = |D_t| $$

　　[確認テスト]
　　　・$ w^{(t+1)} = w^{(t)} - \varepsilon \nabla E $　の式の意味を図に書いて説明せよ。


![スクリーンショット 2021-07-15 22.53.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221503/b9d546d0-38bc-f298-c118-0b77a1fd2d47.png)

　
<dt>4-4.誤差勾配の計算</dt>

 ```math
 \nabla E = \frac{\partial　E}{\partial w} = 
 \Big[ \frac{\partial E}{\partial w_1} \cdots \frac{\partial E}{\partial w_M}
 \Big]
 ```

　●重みはニューラルネットワークの中で大量に出てくる。
　　Eの情報をもとに各重みを計算していく必要がある。
　　その計算方法として微分を使う。

　　○【数値微分】
　　　　プログラムで微小な数値を生成し、擬似的に微分を計算する手法

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

　　　　数値微分である重みの場所(上の式でいうm番目)の重みの間違いがどれくらいか数値微分する場合、
　　　　重みをわずかに(h)増やした時と減らした時の誤差関数を計算し、差し引いた後僅かな値(h)の２倍で割る。

　　　■数値微分のデメリット
　　　・各パラメータ $w_m$ それぞれについて $E(w_m + h)$ や $E(w_m - h)$ を計算するために、
　　　　　順伝播の計算を繰り返し行う必要があり、負荷が大きい
　　　　⇨解決策：**誤差逆伝播法**を利用する

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

![スクリーンショット 2021-07-15 23.23.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221503/7f5a2a82-3292-7287-de2e-e1c626fa2f68.png)

![スクリーンショット 2021-07-15 23.24.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221503/75fa7e8f-7c99-7a7c-8680-115e0bcc7cb5.png)

　　　■計算結果（=誤差）から微分を逆算することで、不要な再帰的計算を避けて微分を算出できる

　　[確認テスト]
　　　誤差逆伝播法では不要な再帰的処理を避ける事が出来る。
　　　既に行った計算結果を保持しているソースコードを抽出せよ。

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

　●誤差勾配の計算式

　　　誤差関数=二乗誤差関数
  
  ```math
  E(y) =  \frac{1}{2} \sum_{j=1}^{J} (y_j - d_j)^2 
  = \frac{1}{2} || y-d ||^2
  ```

　　 　出力層の活性化関数＝恒等写像

   $$ y = u^{(L)} $$

　　　　総入力の計算

   $$ u^{(l)} = w^{(l)} z^{(l-1)} + b^{(l)} $$

　　　　誤差逆伝播

  ```math
   \frac{\partial E}{\partial w_{ji}^{(2)}} = \frac{\partial E}{\partial y}
   \frac{\partial y}{\partial u} \frac{\partial u}{\partial w_{ji}^{(2)}}
  ```

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

   ```math
    \frac{\partial y(u)}{\partial u} = \frac{\partial u}{\partial u}  = 1
   ```

   ```math
   \begin{eqnarray}
    \frac{\partial u(w)}{\partial w_{ji}} &=& \frac{\partial}{\partial w_{ji}}
    \big( w^{(l)} z^{(l-1)} + b^{(l)}  \big) \\
    &=& \frac{\partial}{\partial w_{ji}}
    \begin{pmatrix}
    \begin{bmatrix}
     w_{11} z_1 + & \cdots  +& w_{1i} z_i + & \cdots w_{1I} z_I \\
     & & \vdots \\
     w_{j1} z_1 + & \cdots  +& w_{ji} z_i + & \cdots w_{jI} z_I \\
     & & \vdots \\
     w_{J1} z_1 + & \cdots  +& w_{Ji} z_i + & \cdots w_{JI} z_I \\
    \end{bmatrix}
     +
    \begin{bmatrix}
     b_1 \\
     \vdots \\
     b_j \\
     \vdots \\
     b_J
    \end{bmatrix}
   \end{pmatrix} \\
     &=&
     \begin{bmatrix}
     0 \\
     \vdots \\
     z_i \\
     \vdots \\
     0
    \end{bmatrix}
   \end{eqnarray} 
  ```

 ```math
  \frac{\partial E}{\partial y} \frac{\partial y}{\partial u}
  \frac{\partial u}{\partial w_{ji}^{(2)}} = (y - d) \cdot 
  \begin{bmatrix}
   0 \\
   \vdots \\
   z_i \\
   \vdots \\
   0
  \end{bmatrix}
  = (y_j - d_j) z_i
 ```

　　[確認テスト]

　　 $$ \frac{\partial E}{\partial y} \frac{\partial y}{\partial u} $$
  
　　　　の式をソースコードから抜き出せ、また、

  $$   \frac{\partial E}{\partial y} \frac{\partial y}{\partial u}
       \frac{\partial u}{\partial w_{ji}^{(2)}} $$


　　　　の式もソースコードから抜き出せ。


  ```python
    delta1 = np.dot(delta2, W2.T) * functions.d_sigmoid(z1)
  ```
 
  ```python
    grad['W1'] = np.dot(x.T, delta1)
  ```