# Deep Neural Network (DNN)
###### tags: `python` `Deep Learning`
---
>
>* **本文內容為“Tibame提升AI實作能力必備,深度學習TensorFlow基礎與應用”為主,版權為陳少君所有,本文僅做筆記用途,非商業用途**
>
>* **本篇圖片部分出自“Tibame提升AI實作能力必備,深度學習TensorFlow基礎與應用”課程內容講義**
>
---
# :memo: Introduction
神經網路即為在做自動特徵轉換,比方辨別人臉,機器經過大量Data學習會知道有眼睛、鼻子、嘴巴...等"圖像"特徵,當中間隱藏層數越多可以抓到更細節的特徵,也會讓準確度增加
從神經網路到DNN神經網路的發展中,其關鍵為增加隱藏層,隱藏層越多可以自動抓出高階的特徵值
缺點:當隱藏層越多運算量也會增加,會影響效率
以Hierarchical Feature Learning為例:

# DNN建構
DNN資料走向為向前傳遞性(Forward Propagation),資料流一向由左至右,為單一流向

**公式**
$$
Z = \sigma(W^T·X+b)
$$
其中,
Z為輸出數量(M,1)
W為特徵向量之權重
W^T^為轉置矩陣(M,D)
X為特徵數量(D,1)
b為一常數(M,1)
$\sigma$()為對矩陣每一元素執行的function(active function)
## DNN驗證步驟
Step1. 建模並預測結果Prediction = Round(σ(WTX+b))
Step2. 用Keras的Dense layer 實現
Step3. 經由呼叫Compile(),指定優化器optimizer(adam),損失函數loss(sparse_categorical_crossentropy),量度方式metrics(accuracy)
Step4. 經由呼叫Fit()得到歷程物件(history object),可用來以繪圖程式庫如matplotlib 畫每個迴圈的損失loss,觀察趨勢,決定模型好壞
Step5. 利用model.predict()做預測
:::spoiler Mnist數字集範例
```python=
#Step1. 載入數據
import tensorflow as tf
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
#MNIST儲存28X28X256灰階 0-9 10種數字,其數值需調整成0~1
```
Output
```
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step
11501568/11490434 [==============================] - 0s 0us/step
```
```python=
#Step2. 建立模型
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10, activation='softmax')
])
# tf.keras.layers.Flatten可將28x28扁平化成1x784
# 第一層tf.keras.layers.Dense(神經元數量, activation函數)
# 第二層tf.keras.layers.Dropout(拿掉多少% data)
# 第三層tf.keras.layers.Dense(Output數量, activation函數)
```
```python=
# Step3. 訓練模型
# 編譯模型
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# 訓練模型
r = model.fit(x_train, y_train, validation_data=(x_test, y_test), epochs=10)
```
Output
```
Epoch 1/10
1875/1875 [==============================] - 12s 5ms/step - loss: 0.2948 - accuracy: 0.9144 - val_loss: 0.1567 - val_accuracy: 0.9522
Epoch 2/10
1875/1875 [==============================] - 5s 3ms/step - loss: 0.1430 - accuracy: 0.9576 - val_loss: 0.1030 - val_accuracy: 0.9691
Epoch 3/10
1875/1875 [==============================] - 5s 3ms/step - loss: 0.1080 - accuracy: 0.9677 - val_loss: 0.0869 - val_accuracy: 0.9714
Epoch 4/10
1875/1875 [==============================] - 5s 3ms/step - loss: 0.0886 - accuracy: 0.9728 - val_loss: 0.0763 - val_accuracy: 0.9752
Epoch 5/10
1875/1875 [==============================] - 5s 3ms/step - loss: 0.0738 - accuracy: 0.9774 - val_loss: 0.0716 - val_accuracy: 0.9775
Epoch 6/10
1875/1875 [==============================] - 5s 3ms/step - loss: 0.0647 - accuracy: 0.9789 - val_loss: 0.0696 - val_accuracy: 0.9790
Epoch 7/10
1875/1875 [==============================] - 5s 3ms/step - loss: 0.0575 - accuracy: 0.9816 - val_loss: 0.0672 - val_accuracy: 0.9795
Epoch 8/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0537 - accuracy: 0.9821 - val_loss: 0.0701 - val_accuracy: 0.9769
Epoch 9/10
1875/1875 [==============================] - 5s 3ms/step - loss: 0.0498 - accuracy: 0.9833 - val_loss: 0.0744 - val_accuracy: 0.9781
Epoch 10/10
1875/1875 [==============================] - 5s 3ms/step - loss: 0.0445 - accuracy: 0.9852 - val_loss: 0.0745 - val_accuracy: 0.9774
```
```python=
# 繪出每次迭代的損失
import matplotlib.pyplot as plt
plt.plot(r.history['loss'], label='loss')
plt.plot(r.history['val_loss'], label='val_loss')
plt.legend()
```

```python=
# 繪出每次迭代的精準度
plt.plot(r.history['accuracy'], label='acc')
plt.plot(r.history['val_accuracy'], label='val_acc')
plt.legend()
```

```python=
# 評估模型
print(model.evaluate(x_test, y_test))
print(model.predict(x_test))
```
:::
# Loss Function(損失函數)
目的:判斷模型精準度,損失函數越低準確度越高
## 目標函數(Object function)
機器學習大部分目標函數都是最大化/最小化函數
深度學習大部分目標函數都是損失函數
而損失函數分為Classification & Regression,皆希望最小化損失函數
常用之損失函數:MSE(適用於回歸), MAE, Cross-Entropy(適用於分類)...等
**MSE**

公式:
$$
MSE = \frac{1}{N}\sum_{i=1}^n(y_i-\hat{y_i})^2
$$
其中,
$e_i = y_i-\hat{y_i}$
$e_i$為誤差(error)
**Entropy**
機率密度函數為$p(x)$
Information gain:$I(x)=-log_2(p(x))$
Entropy為接收所有訊息中所有平均訊息量
$$
Entropy=-\sum_{i=1}^Cp_i*log_2(p_i)
$$
其中,
C為所有事件

**Cross-Entropy**
在分類問題時會用Cross-Entropy,以股票為例,假設有分股票漲、跌、平盤
公式為:
$$
\text {Cross-entropy}=-\frac{1}{N}\sum_{i=1}^C\sum_{j=1}^Nt_{i,j}*log(p_{i,j})
$$
其中,
N為所有Data數量(台積電第一天、第二天...等)
C為種類別(漲、跌、平盤)
$t_{i,j}$為binary(0,1),依照真實狀況判別(假,真)
$p_{i,j}$為按照模型推斷之機率(第n天漲的機率,跌的機率...等)
**結論:cross-entropy值越小,表示模型的推斷越準確**
:::spoiler MSE範例
```python=
def MSE(y_predicted, y):
squared_error = (y_predicted - y)**2
sum_squared_error = np.sum(squared_error)
mse = sum_squared_error/y.size
return(mse)
```
:::
# Optimization
## Gradient Decent
**Batch**
Batch為抽樣後的Data,好處為抽樣完要做參數調整時不會更動到抽樣Data
Batch Size:模型內參數調整前需要抽樣數目
Batch Gradient Decent:每一組抽樣都是同一組batch
Stochastic gradient descent(SGD):每一組抽樣都是"獨立"一組batch
mini batch Gradient Decent:有參雜到的batch
**Epoch**
訓練過程中的迴圈數,次數越多損失函數會持續下降,準確度相對提高

**Gradient Decent Algorithm**
Gradient(斜率):$\frac{\partial loss}{\partial w}$
其中,$w$為參數之權重
求loss最小值,Gradient=0時,$w$為最佳解

**Learning rate**
學習率太快會無法收斂,而學習率太慢則也會影響效率,因此需要選擇優化器
優化器有分:固定超參數、可程式控制、自適應,當數據很稀疏時,用自適應較佳
如果數據是稀疏的,就用自適應方法,即Adagrad, Adadelta, RMSprop, Adam
Adam 就是在RMSprop的基礎上加了bias-correction 和momentum,
隨著梯度變的稀疏,Adam 比RMSprop效果會好
**整體來講,Adam 是最好的選擇**
很多論文裡都會用SGD,沒有momentum
SGD雖然能達到極小值,但是比其它算法用的時間長,而且可能會被困在鞍點
由下圖可知各個演算法所產生之效率,其中RMSPROP為最佳

::: spoiler 優化器範例
```python=
import tensorflow as tf
opt = tf.keras.optimizers.SGD(learning_rate=0.1)
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(num_hidden, activation='relu'))
model.add(tf.keras.layers.Dense(num_classes, activation='sigmoid’))
loss_fn = lambda: tf.keras.losses.mse(model(input), output)
var_list_fn = lambda: model.trainable_weights
for input, output in data:
opt.minimize(loss_fn, var_list_fn)
```
:::
## Backpropagation(反向傳播)
Backpropagation是一種常見用來訓練人工神經網路的方法之一
原理:對神經網路中所有權重值來計算損失函數的梯度,而這個梯度會反饋給最優化方法來更新權重值,以達到最小化損失函數之目的
機器學習詳細步驟如下,以linear Classification,將output layer backpropagate to hiden layers,再利用優化器(SGD)來自動調整參數

## Activation Functions
Activation Functions使神經元呈現非線性化(方便做參數調整),完成分類群聚等功能,例如Sigmoid(), Tanh(),但也需要去克服兩種問題:
1. 標準化(Standardization)問題:為了讓神經層與層之間可以傳遞,input與Output之資料分布需要一致(防止值放大或縮小),最好是z分佈(N(0,1)),而Sigmoid是(0,1),tanh是(-1,1)
2. 梯度消失(Vanishing Gradient)問題:當隱藏層變多,在做Backpropagation時,因為梯度下降,導致學習速度降低(收斂),靠近input的隱層層無法更新權重,導致學習準確度不佳,要解決梯度消失目前可用(ReLU)來做解決
- 註:z分佈(N(0,1))平均值$\bar{X}$為0,一個標準差為1
ReLU可解決消失的梯度,但均值大於零非標準化,所以有:Leaky ReLU (LReLU), ELU等嘗試解決。
但ReLU是預設值。其他還有Softplus, BRU(Biological Root Unit)等解決方法

## Regulation
**Lagrange求極值**
Lagrange是達成梯度下降優化的一種方法
Lagrange極值定理
$$
\frac{\partial f(x,y)}{\partial x}=\frac{\partial f(x,y)}{\partial y}=0
$$
當其方程式被$g(x,y)=0$所限制時,會將方程式改寫為
$$
\frac{\partial (f(x,y)+\lambda g(x,y))}{\partial x}=0
$$
$$
\frac{\partial (f(x,y)+\lambda g(x,y))}{\partial y}=0
$$
$$
g(x,y)=0
$$
Ex:$f(x,y)=x+y$,其限制條件為:$h(x,y)=x^2+y^2-32=0$
得到解$(x,y,\lambda)=\pm(4,4,1/8)$
**Regularization**
正則化是機器學習和深度學習皆會用來解決Overfitting的方法
Lasso Regression (L1 norm):
$$
\sum_{i=1}^n(y_i-\hat{y_i})^2=\sum_{i=1}^n(y_i-\sum_{j=0}^pw_j\times x_{ij})^2+\lambda \sum_{j=0}^p|w_j|
$$
Ridge Regression (L2 norm):
$$
\sum_{i=1}^n(y_i-\hat{y_i})^2=\sum_{i=1}^n(y_i-\sum_{j=0}^pw_j\times x_{ij})^2+\lambda \sum_{j=0}^p|w_j|
$$
**Dropout**
將某些比例隱藏神經元關閉來防止overfitting

**Batch normalization**
定義:訓練DNN時將每批輸入(mini-batch)標準化
優點1:減少隱藏層中值的飄移產生的covariance shift數量變動
優點2:每層自主學習不會互相影響
優點3:正則化可不需dropout來減少overfitting問題
# TensorBoard
TensorBoard是Tensorflow的可視化工具包,提供機器學習實驗所需之可視化功能和工具