Deep Learning Specialization (Coursera) 自習記録 (C1W3)

# はじめに
[Deep Learning Specialization](https://www.coursera.org/specializations/deep-learning) の Course 1, Week 3 (C1W3) の内容です。

# (C1W3L01) Newral Network Overview
## 内容

- Week 3 は neural network の実装に関する説明
- Newral Network の 1 層目について
    - $W^{[1]}$, $b^{[1]}$ ; パラメタ
    - $z^{[1]} = W^{[1]} x + b^{[1]}$
    - $a^{[1]} = \sigma(z^{[1]})$
- Neural Network の 2 層目について
    - $z^{[2]} = W^{[2]} a^{[1]} + b^{[2]}$
    - $a^{[2]} = \sigma(z^{[2]})$
    - $L(a^{[2]}, y)$ を計算
- back propagation は
    - $da^{[2]}$ → $dz^{[2]}$ → $dW^{[2]}$, $db^{[2]}$ → …


# (C1W3L02) Neural Network Representation
## 内容
- single hidden layer (= 2 layer neural network，layer を数えるときは，input layer はカウントせず，hidden layer と output layer をカウントする) の説明
- input layer ; $x = a^{[0]}$
- hidden layer
    - パラメタは $w^{[1]}$ ((4, 3) 行列) と $b^{[1]}$ ((4, 1) 行列)
    - $a^{[1]}$ は 4 ノードとする
- output layer
    - パラメタは $w^{[2]}$ ((1, 4) 行列) と $b^{[1]}$ ((1, 1) 行列)
    - $\hat{y} = a^{[2]}$

# (C1W3L03) Computing a Neural Network Output
## 内容
- neural network の計算方法の説明
- $a_i^{[l]}$ ; $l$ layer の，$i$ 番目のノード
- vectorizing (ベクトル化) して計算する

```math
z^{[1]} = W^{[1]} x + b^{[1]} \\
a^{[1]} = \sigma(z^{[1]}) \\
z^{[2]} = W^{[2]} a^{[1]} + b^{[2]} \\
a^{[2]} = \sigma(z^{[2]}) \\
```

# (C1W3L04) Vectorizing Across Multiple Examples
## 内容
- 複数の training example の計算方法
- $X = \[x^{(1)} \, x^{(2)} \, \cdots x^{(m)}\]$ とする ($(n_x, m)$ 行列，$m$ は training example の数)


```math
Z^{[1]} = W^{[1]} X + b^{[1]} \\
A^{[1]} = \sigma\left(Z^{[1]}\right) \\
Z^{[2]} = W^{[2]} Z^{[1]} + b^{[2]} \\
A^{[2]} = \sigma\left(Z^{[2]}\right)
```

- $Z^{[1]}$ ， $A^{[1]}$ は
    - 行 ; hidden unit の数
    - 列 ; $m$

```math
Z^{[1]} = \left[ z^{[1](1)} \, z^{[1](2)} \, \cdots z^{[1](m)} \right] \\
A^{[1]} = \left[ a^{[1](1)} \, a^{[1](2)} \, \cdots a^{[1](m)} \right]
```

## 感想
- 非常にゆっくり，丁寧に説明している。ここが大事だし，躓くと後々大変困るのだろう


# (C1W3L05) Explanation For Vectorized Implementation
## 内容

```math
X = \left[x^{(1)} \, x^{(2)} \, \cdots x^{(m)}\right] \\
Z^{[1]} = \left[z^{[1](1)} \, z^{[1](2)}\, \cdots z^{[1](m)}\right] \\
Z^{[1]} = W^{[1]} X + b^{[1]}
```
- $b^{[1]}$ は Python のブロードキャストを使ってマトリックスになる

# (C1W3L06) Activation functions
## 内容

- sigmoid 関数
    - $a = \frac{1}{1+e^{-z}}$
    - バイナリ分類のときくらいしか使わない

- tanh 関数
    -  $a = \tanh z = \frac{e^z - e^{-z}}{e^z + e^{-z}}$
    - sigmoid 関数よりベター。平均値がゼロになるから。
    - ただし，sigmoid 関数と tanh 関数の共通の欠点は，$z$ が大きいところで傾きが 0 に近づくため，最急降下法の収束が遅くなる

- ReLU 関数
    - $a = \max\(0, z\)$
    - $z=0$ で微分を定義できないが，計算時に厳密に $z=0$ になることはないので，問題ない。
    - ReLU が neural netwok　ではデフォルトで使われる (たまに tanh)
    - $z \lt 0$ で傾きが 0 になるのが欠点

- Leaky ReLU
    - $a = \max(0.01z, z)$
    - $z \lt 0$ でもわずかに傾きを持たせる
    - 0.01 を学習パラメタの 1 つと見なすこともできるが，それを実装する人はほとんどいない
- layer によって activation function を変えることもある (hidden layer を tanh，output layer を sigmoid など)
- Neural network には選択するものが多い (activation function の種類，パラメタの初期化方法，など) が，そのガイドラインを示すことは難しい

# (C1W3L07) Why do you need non-linear activation function
## 内容

- なぜ，activation function に非線形関数を使うのか? → 線形関数にすると，hidden layer を増やしても，結局のところ線形関数にしかならないので，役に立たない

# (C1W3L08) Derivatives of activation functions
## 内容

- sigmoid activation function

```math
g(z) = \frac{1}{1+e^{-z}} \\
g^\prime(z) = g(z) \left( 1-g(z) \right)
```
- Tanh activation function

```math
g(z) = \tanh (z) \\
g^\prime(z) = 1-\left( \tanh(z) \right)^2
```
- ReLU

```math
g(z) = \max\left(0, z\right) \\
g^\prime(z) = 0 \ (\text{if}\  z \lt 0) \\
g^\prime(z) = 1 \ (\text{if}\  z \ge 0)
```
- Leaky ReLU

```math
g(z) = \max\left(0.01z, z\right) \\
g^\prime(z) = 0.01 \ (\textrm{if}\  z \lt 0) \\
g^\prime(z) = 1 \ (\textrm{if}\  z \ge 0)
```

- ReLU や Leaky ReLU の $z=0$ の微分については，0 でも 1 でも不定でも構わない (計算中に厳密に $z=0$ になる確率は低いため)


# (C1W3L09) Gradient descent for neural network
## 内容

- $n^{[0]} = n_x, n^{[1]}, n^{[2]} (=1)$ とする
- パラメタは $W^{[1]}$ ($(n^{[1]}, n^{[0]})$ 行列)，$b^{[1]}$ ($(n^{[1]}, 1)$ 行列)，$W^{[2]}$ ($(n^{[2]}, n^{[1]})$ 行列)，$b^{[2]}$ ($(n^{[2]}, 1)$ 行列)
- cost function ; $J(W^{[1]}, b^{[1]}, W^{[2]}, b^{[2]}) = \frac{1}{m}\Sigma_{i=1}^{m}L(\hat{y}, y)$
- Forword propagation (output layer はバイナリ分類 → シグモイド関数)

```math
Z^{[1]} = W^{[1]} X + b^{[1]} \\
A^{[1]} = g^{[1]}\left( Z^{[1]} \right) \\
Z^{[2]} = W^{[2]} A^{[1]} + b^{[2]} \\
A^{[2]} = g^{[2]}\left( Z^{[2]} \right) = \sigma \left( Z^{[2]} \right) 
```

-backpropagation

```math
dZ^{[2]} = A^{[2]} - Y \ \ \left( Y = \left[ y^{(1)} \, y^{(2)} \, \cdots y^{(m)} \right] \right) \\
dW^{[2]} = \frac{1}{m} dZ^{[2]} A^{[1]\textrm{T}}\\
db^{[2]} = \frac{1}{m} \textrm{np.sum} \left( dZ^{[2]} \textrm{, axis=1, keepdims=True} \right)\\

dZ^{[1]} = W^{[2]\textrm{T}}dZ^{[2]} \ast g^{[1]\prime} \left(Z^{[1]}\right) \\
dW^{[1]} = \frac{1}{m}dZ^{[1]} X^{\text{T}} \\
db^{[1]} = \frac{1}{m} \textrm{np.sum} \left( dZ^{[1]} \textrm{, axis=1, keepdims=True} \right)\\
```

- ```np.sum``` の ```keepdims=True``` を付けないと，$(n^{[i]}, )$ ベクトルになる。```keepdims=True``` を付けると $(n^{[i]}, 1)$ ベクトルになる。
- ```keepdims=True``` を付けないなら，```reshape``` する
- $dZ^{[1]}$ の式の $\ast$ は，要素ごとの積

## 感想
- さりげなく ```np.sum``` の Tips を織り交ぜている (dimension を意識するのは大事)


# (C1W3L10) Backpropagation Intuition (optional)
## 内容

- logistic regression の backpropagation の vectorized implementation の直感的な説明
- 「neural network のもっとも数学的に難しいところ」とのこと

# (C1W3L11) Random Initialization
## 内容

- logistic regression のときは重みを 0 で初期化しても OK
- neural network では重み W を 0 で初期化するのは NG
- 仮に $W^{[1]}$ の要素が全て 0，$b^{[1]}$ の要素も全て 0 とすると，hidden layer のユニットがいくつあっても，すべて同じ計算をすることになる。そうなると複数のユニットを持つ意味がなく，単一のユニットしかない場合と同じになってしまう
- 初期化方法

```math
W^{[1]} = \textrm{np.random.randn(2, 2)} \ast 0.01 \\
b^{[1]} = \textrm{np.zero((2, 1))}
```

- $W^{[1]}$ がランダムに初期化されれば対称性が崩れるので，$b^{[1]}$ は 0 でも良い
- $W$ の初期値は小さいほうが良い。$W$ が大きいと，$Z = Wx + b$ が大きくなるが，sigmoid や $\tanh$ は値が大きいと傾きが小さくなり，最急降下法の学習速度が遅くなる
- hidden layer が 1 つなど浅い neural network では，0.01 で OK。深い neural network のときは，0.01 以外の値の場合もある

# 参考
- [Deep Learning Specialization (Coursera) 自習記録 (目次)](https://qiita.com/satomshr/items/dc4ae752c558798bbef6)