神經網路詳解及技巧
阿新 • • 發佈:2020-04-04
[TOC](神經網路)
# 前言
筆者一直在ipad上做手寫筆記,最近突然想把筆記搬到部落格上來,也就有了下面這些。因為本是給自己看的筆記,所以內容很簡陋,只是提了一些要點。隨緣更新。
# 正文
## step1 建立一個神經網路模型
###### 一個常見的神經網路——完全連線前饋神經網路
- 全連線:layer和layer之間兩兩連線
- 前饋傳遞方向由後向前,任意兩層之間沒有反饋
- 深度:許多隱含層
$\sigma(\begin{bmatrix}1&-2 \\-1&1\end{bmatrix}\begin{bmatrix}1 \\-1\end{bmatrix}+\begin{bmatrix}1 \\0\end{bmatrix})=\begin{bmatrix}0.98 \\0.12\end{bmatrix}$ 如此一層一層傳遞下去。
最普通的啟用函式$\sigma(z)$為sigmoid函式
$$f(z)=\frac{1}{1+e^{-z}}$$
其影象為:
當然,現在已經很少使用sigmoid函式做啟用函數了。
#### 本質
通過隱含層來代替原來的特徵工程,這樣最後一個隱含層輸出的就是一組新的特徵,然後通過一個多分類器(可以是$solfmax$函式)得到最後的輸出$y$。
###### 舉例:手寫識別
## step2 模型評估
對於神經網路,我們採用交叉熵來對 $y$ 和 $\hat y$ 的損失進行計算。(後期我將在生成模型和判別模型中對他進行詳細的描述)
## step3 最佳模型——梯度下降
$backpropation$(反向傳播,也就是所謂的$BP$)在神經網路中是一種有效的方式計算$\frac{\partial{L}}{\partial w}$的方式,我們可以利用很多框架進行計算,如:TensorFlow,Pytorch。
## 反向傳播($BP$)
$L(\theta)$是總體損失函式,$l^n(\theta)$是單個樣本產生的誤差。
計算$L(\theta)= \sum_{n=0}^{N}l^n(\theta)$,只需要計算$\frac{\partial L(\theta)}{\partial w}=\sum_{n=1}^{N}\frac{\partial L(\theta)}{\partial w}$。
##### 我們取出一個神經元進行分析
易得:
$$\frac{\partial l}{\partial w}=\frac{\partial z}{\partial w}\frac{\partial l}{\partial z}$$
##### Forward Pass $\frac{\partial z}{\partial w}$:
這裡我可以很輕鬆看出$\frac{\partial z}{\partial w}$為上一隱含層輸出的值。
##### Backward Pass $\frac{\partial l}{\partial z}$:
$$\frac{\partial l}{\partial z}=\frac{\partial a}{\partial z}\frac{\partial l}{\partial a} = \frac{\partial a}{\partial z}[\frac{\partial z'}{\partial a}\frac{\partial l}{\partial z}+\frac{\partial z''}{\partial a}\frac{\partial l}{\partial z''}] = \sigma'(z)[w_3 \frac{\partial l}{\partial z'} + w_4 \frac{\partial l}{\partial z''}]$$
這時候我們會覺得每計算一次梯度相當麻煩,每個引數的梯度都需要層層往後計算,計算量大到無法想象。實際上進行Backward Pass和向前傳播的計算量差不多,我們只需將我們的思維逆轉一下,從最後一層往前計算,也能計算出所有引數的梯度,這時的計算量是線性的,這就是 $BP$ 的思想(個人為很類似於演算法中的動態規劃)。
## 利用keras建立神經網路
建立神經網路的過程,別人以為你在搞什麼特別深奧高大上的東西,其實你只是在搭積木一樣一層一層疊隱含層而已=。=
```python
import keras
from keras.models import Sequential
from keras.layers import Dense
model = Sequential() # 建立一個模型
# 搭建網路
'''@param
Dense: Fully connect layer
input_dim: 輸入層
units: 神經元
activation: 啟用函式
'''
model.add(Dense(input_dim=10, units=500, activation='sigmoid')) # 建立一個神經網路
# 再加一個隱含層
model.add(Dense(units=500, activation='sigmoid'))
# 輸出層
model.add(Dense(units=10, activation='softmax')) # 輸出向量長度為10,啟用函式為softmax
# loss function
model.compile(loss='categotial_crossentropy', # 損失函式:交叉熵
optimizer='adam', # 優化器(都是梯度下降)
metrics=['accuracy'] # 指標
)
# batch_size: 將訓練集隨機分為分為幾個batch,每次計算隨機的一個
# 所有batch都計算一次,一個epoch結束
model.fit(x_train, y_train, batch_size=100, epochs=20)
# case1: 測試集正確率
score = model.evaluate(x_test, y_test)
print('Total loss on Test Set:', score[0])
print('Accuracy of Testing Set:', score[1])
# case 2:模型預測
result = model.predict(x_test)
```
## 深度學習的技巧
### 在test上如何改進:
#### 新的啟用函式
###### sigmoid缺點——梯度消失:
有時神經網路層數越深,結果越差,原因可能是梯度消失,比較靠近input的幾層梯度很小,靠近output的幾層梯度較大,在前幾層還未怎麼更新引數時,後幾層已經收斂。因為每經過一個sigmoid,$\Delta w$的影響就會被消弱。
###### ReLU:
- 當 input > 0 時,output = input
- 當 input < 0 時,output = 0
在input < 0 時,相當於該節點被移除,整個網路就是 a thinner linear network,如果時線性的話,梯度不會遞減。
你可能會說這個線性模型如何處理那些複雜的非線性模型,畢竟不是所有問題都和線性一樣美好,你要注意了我們這是deep learning,關鍵在於這個“deep”,這是一個有著數層幾千個神經元的網路,它們疊加的效果就是一個非線性的模型,是一個很複雜的function。對於ReLU activation function的神經網路,只是在小範圍內是線性的,在總體上還是非線性的。
好處:
1. 比sigmoid處理起來快
2. 無窮多的sigmoid疊加起來的結果(不同的bias)
3. 可以處理梯度消失
變種:
- Leaky ReLU
- Parametric ReLU
###### Maxout —— 讓network自動學習的啟用函式
方法:
1. 先將輸入分組,如2個一組或3個一組
2. 再從每一組中選擇最大的一個
下圖為一個簡單的示例
原理:
其實上面介紹的ReLU為一個特殊的Maxout,理論上Maxout可以擬合任何啟用函式
比如下面這個ReLU可以由如此的Maxout得到
選擇不同的$w$和$b$可以做到
你可能會問這樣不就有的節點訓練不到了嗎?因為有些節點的權值為0等於從網路中去除了。其實只是部分資料上此節點為0,但是我們有大量資料,總有資料可以訓練到這個節點。所以 $Maxout$ 需要比 $ReLU$ 更大的資料量才能訓練好這個網路。
#### 更新學習速率
##### RMSProp
屬於之前線上性模型中提到的$Adagrad$演算法的變形
$$w^1 \longleftarrow w^0 - \frac{\eta}{\sigma^0}g^0 \qquad \sigma^0=g^0$$
$$w^2 \longleftarrow w^1 - \frac{\eta}{\sigma^1}g^1 \qquad \sigma^1=\sqrt{\alpha(\sigma^0)^2+(1-\alpha)(g^1)^2}$$
$$w^3 \longleftarrow w^2 - \frac{\eta}{\sigma^2}g^2 \qquad \sigma^2=\sqrt{\alpha(\sigma^1)^2+(1-\alpha)(g^2)^2}$$
$$......$$
$$w^{t+1} \longleftarrow w^t - \frac{\eta}{\sigma^t}g^t \qquad \sigma^t=\sqrt{\alpha(\sigma^{t-1})^2+(1-\alpha)(g^t)^2}$$
一個固定的learning rate除以一個$\sigma$(在第一個時間點,$\sigma$就是第一個算出來GD的值),在第二個時間點,你算出來一個$g^1$和 $\sigma^2$(你可以去手動調一個$\alpha$值,把$\alpha$值調整的小一點,說明你傾向於相信新的gradient告訴你的這個error surface的平滑或者陡峭的程度)。
##### Momentum
參考了物理世界慣性的概念,遇到一個小山坡時可以通過慣性翻過,從而越過區域性最優點。
在演算法中只參考上一次的速度,因為上一次的速度已經包含了之前所有的速度。
步驟:
1. 選擇一個初始位置 $\theta^0$ 和初始速度 $v^0=0$
2. 計算在 $\theta^0$ 處的梯度$\Delta L(\theta^0)$
3. $v^1=\lambda v^0-\eta\Delta L(\theta^0)$
4. $\theta^0= \theta^1+v^1$
5. 如此往復
##### Adam
$RMSProp$和$Momentum$的結合。有興趣的朋友直接看圖吧。
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200401235312204.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzkwMTIyMQ==,size_16,color_FFFFFF,t_70)
### 在train上改進(過擬合)
##### Early Stopping
我們需要的是測試集錯誤最小,而不是訓練集,如果測試集的Loss上升,則需要立刻停止訓練,但是如果將測試集加入訓練則會導致測試結果不客觀。這時我們可以引入驗證集來解決。當訓練時驗證集Loss上升則停止訓練。
##### Regularization
和線性模型一樣,我們需要在原來的$loss function$加入正則化,讓得到的結果更加平滑。
常見的有$L_1-norm$(一次式)和$L_2-norm$(二次式)
##### Dropout
###### 如何訓練
在訓練時的時候,每一次引數更新之前,對network裡面的每個神經元(包括輸入層),做取樣(sampling)。 每個神經元會有p%的可能性會被丟掉,跟著的 $w$ 也會被丟掉。
###### 解釋
你在訓練時,加上dropout,你會看到在訓練集上結果會變得有點差(因為某些神經元不見了),但是dropout真正做的事就是讓你測試集越做越好。
假設有$m$個神經元,就可以訓練 $2^m$ 個神經網路結構,每個網路的偏差雖然很大,但是最後平均下來還是很準的(這個又要回到我們線上性模型中說的 $varience$ 和 $bias$ 問題)。
dropout其實是用了模型融合(model essemble)的思想,訓練了很多模型最後加權得到最終的結果。
###### 在testing上注意兩件事情:
- 第一件事情就是在testing上不做dropout。
- 在dropout的時候,假設dropout rate在training是p%,all weights都要乘以$(1-p\%)$
關於為什麼要乘$(1-p\%)$,舉一個簡單的例子:
# 總結
到此神經網路已經介紹得差不多了,你可能會說,就這,就這?其實神經網路也不是什麼深奧的東西,本質上就是一個有著數千個引數的模型,和最簡單的線性模型一樣,也是通過最常規的方法——梯度下降求解。當然,其中也涉及了一些挺玄學(只可意會,不可言傳,當然也是我的數學功底不夠,無法準確描述)的方法。
上一篇:[機器學習筆記(1)——線性迴歸](https://blog.csdn.net/weixin_43901221/article/details/105211639)
下一篇:可能會講一講CNN或者神經網路中神經元的來源——logistic迴歸(未開始寫=。=)
(如果覺得有用請點個