人工智慧實踐:Tensorflow2.0 新手筆記(2)

一枝花花送給你、發表於2020-12-06

本節目標:學會神經網路的優化過程,使用正則化減少過擬合,使用優化器更新網路引數。

1. 預備知識

(1) tf.where(條件語句, 真返回A, 假返回B)

  • 條件語句,如果條件為真返回A,否則返回B
a = tf.constant([1, 2, 3, 4, 4])
b = tf.constant([0, 1, 3, 4, 5])
c = tf.where(tf.greater(a, b), a, b)   # 對應元素比較
c
執行結果:
<tf.Tensor: shape=(5,), dtype=int32, numpy=array([1, 2, 3, 4, 5])>

(2) np.random.RandomState().rand()

  • 返回一個[0,1)之間的隨機數
    np.random.RandomState().rand(維度)
rdm = np.random.RandomState(seed = 11)  # seed 可以保障每次執行的結果一致
aa = rdm.rand()
bb = rdm.rand()
cc = rdm.rand(2,3)
print(aa)
print(bb)
print(cc)
0.1802696888767692
0.019475241487624584
[[0.46321853 0.72493393 0.4202036 ]
 [0.4854271  0.01278081 0.48737161]]

(3) np.vstack()

  • 將兩個陣列按橫向合併
    np.vstack(陣列1, 陣列2)
rdm = np.random.RandomState(seed = 11)
aa = rdm.rand(2, 3)
bb = rdm.rand(2, 3)
cc = np.vstack((aa, bb))
print(aa)
print(bb)
print(cc)
執行結果:
[[0.18026969 0.01947524 0.46321853]
 [0.72493393 0.4202036  0.4854271 ]]
[[0.01278081 0.48737161 0.94180665]
 [0.85079509 0.72996447 0.10873607]]
[[0.18026969 0.01947524 0.46321853]
 [0.72493393 0.4202036  0.4854271 ]
 [0.01278081 0.48737161 0.94180665]
 [0.85079509 0.72996447 0.10873607]]

(4) np.mgrid[]  .ravel()  np.c_[]

  • np.mgrid[] 返回若干組維度相同的等差陣列網格
     np.mgrid[起始值 : 結束值 : 步長, 起始值 : 結束值 : 步長, … ]
     [起始值,結束值) 前閉後開
  • x.ravel() 將x變為以為陣列
  • np.mgrid[陣列1, 陣列2, …] 使返回值的間隔數值點配對
x, y = np.mgrid[1:3:1, 2:4:0.5]   # 維度一致 所以將x擴充了
print("x = \n", x)
print("y = \n", y)
grid = np.c_[x.ravel(), y.ravel()]
grid
執行結果:
x = 
 [[1. 1. 1. 1.]
 [2. 2. 2. 2.]]
y = 
 [[2.  2.5 3.  3.5]
 [2.  2.5 3.  3.5]]
array([[1. , 2. ],
       [1. , 2.5],
       [1. , 3. ],
       [1. , 3.5],
       [2. , 2. ],
       [2. , 2.5],
       [2. , 3. ],
       [2. , 3.5]])

2. 神經網路複雜度

  • 神經網路(NN)複雜度:多用NN層數和NN引數的個數表示
    • 空間複雜度:
       層數 = 隱藏的層數 + 1個輸出層 (輸入層只是將資料傳輸進來,所以不計入)
       總引數 = 總w個數 + 總b個數
    • 時間複雜度:
       乘加運算次數(有多少權重線)

3. 指數衰減學習率

  • 學習率:
    w t + 1 = w t − l r ∂ l o s s ∂ w t w_{t+1}=w_{t}-lr\frac{\partial loss}{\partial w_{t}} wt+1=wtlrwtloss
w t + 1 w_{t+1} wt+1 w t w_{t} wt l r lr lr ∂ l o s s ∂ w t \frac{\partial loss}{\partial w_{t}} wtloss
更新後的引數當前引數學習率損失函式的梯度(偏導數)
  • 指數衰減學習率:可以先採用較大的學習率,快速得到較優解,然後逐步減小學習率,使模型在訓練後期穩定。
    指 數 衰 減 學 習 率 = 初 始 學 習 率 ∗ 學 習 率 衰 減 率 ( 當 前 次 數 / 多 少 次 衰 減 一 次 ) 指數衰減學習率 = 初始學習率*學習率衰減率^{(當前次數/多少次衰減一次)} =(/)
epoch = 40
LR_BASE = 0.2
LR_DECAY = 0.99
LR_STEP = 1

for epoch in range(epoch):
	lr = LR_BASE * LR_DECAY ** (epoch / LR_STEP)
	with tf.GradientTape() as tape:
		loss = tf.square(w + 1)
	grads = tape.gradient(loss, w)
	
	w.assign_sub =(lr * grads)
	print("after %s epoch, w is %f,loss is %f,lr is %f" 
	% (epoch, w.numpy(), loss, lr))

學習率衰減詳細參考: TENSORFLOW2.0學習率衰減詳細彙總

4. 啟用函式

  • 啟用函式(Activation Function):就是在人工神經網路的神經元上執行的函式,負責將神經元的輸入對映到輸出端。

(1) sigmoid函式:

f ( x ) = 1 1 + e − x f(x) = \frac{1}{1+ e^{-x}} f(x)=1+ex1
sigmoid

  • 優點:
    (1)輸出對映在(0,1)之間,單調連續,輸出範圍有限,優化穩定,可用作輸出層;
    (2)求導容易
  • 缺點:
    (1)易造成梯度消失;
    (2)輸出非0均值,收斂慢
    (3)冪運算複雜,訓練時間長
  • sigmoid函式可應用在訓練過程中。然而,當處理分類問題作出輸出時,sigmoid卻無能為力。簡單地說,sigmoid函式只能處理兩個類,不適用於多分類問題。而softmax可以有效解決這個問題,並且softmax函式大都運用在神經網路中的最後一層網路中,使得值得區間在(0,1)之間,而不是二分類的。

(2) tanh函式:

f ( x ) = 1 − e − 2 x 1 + e − 2 x f(x) = \frac{1- e^{-2x}}{1+ e^{-2x}} f(x)=1+e2x1e2x
tanh

  • 優點:
    (1)比sigmoid收斂更快
    (2)輸出是0均值
  • 缺點:
    (1)易造成梯度消失;
    (2)冪運算複雜,訓練時間長

(3) relu函式:

f ( x ) = m a x ( x , 0 ) { 0 x < 0 x x > = 0 f(x) = max(x,0) \begin{cases} 0 & x<0\\ x & x>=0 \end{cases} f(x)=max(x,0){0xx<0x>=0
tf.nn.relu(x)
relu

  • 優點:
    (1)解決了梯度消失問題(在正區間)
    (2)只需判斷輸入是否大於0,速度快
    (3)收斂速度遠快於sigmoid和tanh
  • 缺點:
    (1)輸出非0均值,又會使收斂慢
    (2)Dead RelU問題,某些神經元可能永遠不會被啟用,導致相應的引數永遠不能更新,神經元死亡。
  • 啟用函式的輸入特徵為負數時,啟用函式的輸出為0,反向傳播得到的梯度是0,導致引數無法更新,造成神經元死亡。其原因是經過relu函式的負數特徵過多導致的,可以改進隨機初始化,避免過多的負數特徵送入relu函式;可以減小學習率,減少引數分佈的巨大變化,避免訓練中
    產生過多負數特徵進入relu函式。

(4) Leak Relu函式:

f ( x ) = m a x ( α x , x ) { α x , x < 0 x x > = 0 f(x) = max(\alpha{x},x) \begin{cases} \alpha{x}, & x<0\\ x & x>=0 \end{cases} f(x)=max(αx,x){αx,xx<0x>=0
tf.nn.leaky_relu(x)
Leak Relu

  • 理論上講,Leaky Relu有 Relu 的所有優點,外加不會有Dead RelU問題,但是在實際操作中,並沒有完全證明Leaky Relu總是浩宇 Relu,所以使用Relu的更多。

(5) 建議:

  • 首選ReLU啟用函式;
  • 學習率設定較小值;
  • 輸入特徵標準化,即讓輸入特徵滿足以0為均值,1為標準差的正態分佈;
  • 初始化問題:初始引數中心化,即讓隨機生成的引數滿足以0為均值, 2 當 前 層 輸 入 特 徵 個 數 \sqrt{\frac{2}{當前層輸入特徵個數} } 2

5. 損失函式

  • 啟用函式:損失函式用來評價模型的預測值和真實值不一樣的程度,損失函式越好,通常模型的效能越好。不同的模型用的損失函式一般也不一樣。神經網路模型的效果及優化的目標是通過損失函式來定義的。迴歸和分類是監督學習中的兩個大類。

(1) 均方誤差損失函式:

  • 均方誤差Mean Square Error):是迴歸問題最常用的損失函式。迴歸問題解決的是對具體數值的預測,比如房價預測、銷量預測等。這些問題需要預測的不是一個事先定義好的類別,而是一個任意實數。
    M S E ( y i , y i ^ ) = ∑ i = 1 n ( y i − y i ^ ) 2 n MSE(y_i,\hat{y_i}) =\frac{ \sum_{i=1}^n{(y_i-\hat{y_i})}^2}{n} MSE(yi,yi^)=ni=1n(yiyi^)2
    其中 y i y_i yi為一個batch中第i個資料的真實值,而 y i ^ \hat{y_i} yi^為神經網路的預測值。
loss_mes = tf.reduce_mean(tf.square(y_-y))

(2) 交叉熵損失函式:

  • 交叉熵Cross Entropy):表徵兩個概率分佈之間的距離,交叉熵越小說明二者分佈越接近,是分類問題中使用較廣泛的損失函式。
    H ( y , y ^ ) = − ∑ ( y ^ ∗ l n y ) H(y,\hat{y}) ={ -\sum({\hat{y}}}*{lny} ) H(y,y^)=(y^lny)

例:
二分類已知答案y_(1,0), 預測 y 1 = ( 0.6 , 0.4 ) y_1 = (0.6,0.4) y1=(0.6,0.4) y 2 = ( 0.8 , 0.2 ) y_2 = (0.8,0.2) y2=(0.8,0.2),哪一個更接近標準答案?
H 1 ( ( 1 , 0 ) , ( 0.6 , 0.4 ) ) = − ( 1 ∗ l n 0.6 + 0 ∗ l n 0.4 ) = 0.511 H_1((1,0),(0.6,0.4)) = -(1*ln0.6+0*ln0.4) = 0.511 H1((1,0),(0.6,0.4))=(1ln0.6+0ln0.4)=0.511
H 1 ( ( 1 , 0 ) , ( 0.6 , 0.4 ) ) = − ( 1 ∗ l n 0.8 + 0 ∗ l n 0.2 ) = 0.233 H_1((1,0),(0.6,0.4)) = -(1*ln0.8+0*ln0.2) = 0.233 H1((1,0),(0.6,0.4))=(1ln0.8+0ln0.2)=0.233

loss_ce1 = tf.losses.categorical_crossentropy([1,0],[0.6,0.4])
loss_ce2 = tf.losses.categorical_crossentropy([1,0],[0.8,0.2])
print(loss_ce1)
print(loss_ce2)
執行結果: 
tf.Tensor(0.5108256, shape=(), dtype=float32)
tf.Tensor(0.22314353, shape=(), dtype=float32)
  • softmax函式與交叉熵函式結合:
    正常流程輸出先過softmax函式,使結果符合概率分佈,再計算y和y_的交叉熵損失函式,Tensorflow給出了可以同時計算softmax概率分佈結果和交叉熵的函式:
tf.nn.softmax_cross_entropy_with_logits(y_,y)

6. 欠擬合與過擬合

欠擬合 正確擬合 過擬合

  • 欠擬合:模型不能有效擬合資料集,對現有資料集學習的不夠徹底;

  • 過擬合:對當前資料集擬合的太強,但對未見過的新資料不能正確預測,缺乏泛化能力。

  • 欠擬合解決方案:
     增加輸入特徵項
     增加網格引數
     減少正則化引數

  • 過擬合解決方案:
     資料清洗,減少噪聲
     增大訓練集
     採用正則化
     增大正則化引數

7. 正則化減少過擬合

《直觀理解,什麼是正則化》
我們總會在各種地方遇到正則化這個看起來很難理解的名詞,其實它並沒有那麼高冷,是很好理解的…

8. 優化器更新網路引數

神經網路是基於連線的人工智慧,當網路結構固定後,不同引數的選取對模型的表達力影響很大,更新模型引數的過程彷彿教一個孩子理解世界,適齡的孩子都具備了學習的條件,但是不同的引導方法會是孩子具備不同的能力。

  • 優化器,就是引導神經網路更新引數的工具。

待優化引數 w w w,損失函式 l o s s loss loss,學習率 l r lr lr,每次迭代的一個 b a t c h batch batch t t t 表示當前 b a t c h batch batch 迭代的總次數,更新引數分為4步完成:
1.計算 t t t時刻損失函式關於當前引數的梯度 g t = ∇ l o s s = ∂ l o s s ∂ w t g_t=\nabla{loss}=\frac{\partial{loss}}{\partial{w_t}} gt=loss=wtloss
2.計算 t t t時刻一階動量 m t m_t mt二階動量 V t V_t Vt
3.計算 t t t時刻下降梯度: η t = l r ⋅ m t / V t \eta_t = {lr}\cdot{{m_t}}/{\sqrt{V_t}} ηt=lrmt/Vt
4.計算 t + 1 t+1 t+1時刻引數: w t + 1 = w t − η t = w t − l r ⋅ m t / V t w_{t+1} = w_{t}-{\eta_t }=w_{t}- {lr}\cdot{{m_t}}/{\sqrt{V_t}} wt+1=wtηt=wtlrmt/Vt

  • 一階動量:與梯度相關的函式
  • 二階動量:與梯度平方相關的函式
  • 不同的優化器,實質上只是定義了不同的一階動量和二階動量公式

(1) SGD:

  • SGD(無momentum),最常用的梯度下降法:

m t = g t m_t = g_t mt=gt         V t = 1 V_t = 1 Vt=1

η t = l r ⋅ m t / V t = l r ⋅ g t \eta_t = {lr}\cdot{{m_t}}/{\sqrt{V_t}} = lr\cdot{g_t} ηt=lrmt/Vt =lrgt

w t + 1 = w t − η t = w t − l r ⋅ m t / V t = w t − l r ⋅ g t w_{t+1} = w_{t}-{\eta_t }=w_{t}- {lr}\cdot{{m_t}}/{\sqrt{V_t}}=w_{t}- lr\cdot{g_t} wt+1=wtηt=wtlrmt/Vt =wtlrgt

最終得到
w t + 1 = w t − l r ∂ l o s s ∂ w t w_{t+1}=w_{t}-lr\frac{\partial loss}{\partial w_{t}} wt+1=wtlrwtloss

(2) SGDM:

  • SGDM(含momentum的SGD),在SGD基礎上增加一階動量。
    m t = β ⋅ m t − 1 + ( 1 − β ) g t m_t = \beta {\cdot}{m_{t-1}}+(1-\beta)g_t mt=βmt1+(1β)gt         V t = 1 V_t = 1 Vt=1

η t = l r ⋅ m t / V t = l r ⋅ m t = l r ⋅ ( β ⋅ m t − 1 + ( 1 − β ) g t ) \eta_t = {lr}\cdot{{m_t}}/{\sqrt{V_t}} = lr\cdot{m_t}={lr}{\cdot}{(\beta {\cdot}{m_{t-1}}+(1-\beta)g_t)} ηt=lrmt/Vt =lrmt=lr(βmt1+(1β)gt)

w t + 1 = w t − η t = w t − l r ⋅ m t = w t − l r ⋅ ( β ⋅ m t − 1 + ( 1 − β ) g t ) w_{t+1} = w_{t}-{\eta_t }=w_{t}- lr\cdot{m_t}=w_{t}- {lr}{\cdot}{(\beta {\cdot}{m_{t-1}}+(1-\beta)g_t)} wt+1=wtηt=wtlrmt=wtlr(βmt1+(1β)gt)

m t m_t mt表示各時刻梯度方向的指數滑動平均,和SGD相比一階動量的公式多了 m t − 1 {m_{t-1}} mt1項(上一時刻的一階動量),且該項在公式中佔比更大,因為 β \beta β是一個超引數,接近1(經驗值為0.9)。

(3) Adagrad:

  • Adagrad,在SGD基礎上增加二階動量

m t = g t m_t = g_t mt=gt         V t = ∑ τ = 1 t g τ 2 V_t = \sum_{{\tau}=1}^t{g_{\tau}^2} Vt=τ=1tgτ2

η t = l r ⋅ m t / V t = l r ⋅ g t / ∑ τ = 1 t g τ 2 \eta_t = {lr}\cdot{{m_t}}/{\sqrt{V_t}} = {lr}\cdot{{ g_t}}/{\sqrt{\sum_{{\tau}=1}^t{g_{\tau}^2}}} ηt=lrmt/Vt =lrgt/τ=1tgτ2

w t + 1 = w t − η t = w t − l r ⋅ g t / ∑ τ = 1 t g τ 2 w_{t+1} = w_{t}-{\eta_t }=w_{t}- {lr}\cdot{{ g_t}}/{\sqrt{\sum_{{\tau}=1}^t{g_{\tau}^2}}} wt+1=wtηt=wtlrgt/τ=1tgτ2

Adagrad是在SGD的基礎上引入二階動量,可以對模型中的每一個引數分配自適應學習率。

(4) RMSProp,SGD基礎上增加二階動量

m t = g t m_t = g_t mt=gt         V t = β ⋅ V t − 1 + ( 1 − β ) g t 2 V_t =\beta {\cdot}{V_{t-1}}+(1-\beta)g_t^2 Vt=βVt1+(1β)gt2

η t = l r ⋅ m t / V t = l r ⋅ g t / β ⋅ V t − 1 + ( 1 − β ) g t 2 \eta_t = {lr}\cdot{{m_t}}/{\sqrt{V_t}} = {lr}\cdot{{ g_t}}/{\sqrt{\beta {\cdot}{V_{t-1}}+(1-\beta)g_t^2}} ηt=lrmt/Vt =lrgt/βVt1+(1β)gt2

w t + 1 = w t − η t = w t − l r ⋅ g t / ( β ⋅ V t − 1 + ( 1 − β ) g t 2 ) w_{t+1} = w_{t}-{\eta_t }=w_{t}- {lr}\cdot{{ g_t}}/{({\sqrt{\beta {\cdot}{V_{t-1}}+(1-\beta)g_t^2}})} wt+1=wtηt=wtlrgt/(βVt1+(1β)gt2 )

二階動量 V V V使用指數滑動平均值計算,同樣,表徵過去一段時間的平均值

(5) Adam,同時結合SGDM一階動量和RMSProp二階動量

m t = β ⋅ m t − 1 + ( 1 − β ) g t m_t = \beta {\cdot}{m_{t-1}}+(1-\beta)g_t mt=βmt1+(1β)gt

修正一階動量偏差: m t ^ = m t 1 − β 1 t \hat{m_t}=\frac{m_t}{1-{\beta_1^t}} mt^=1β1tmt

V t = β 2 ⋅ V s t e p − 1 + ( 1 − β 2 ) ⋅ g t 2 V_t =\beta_2 {\cdot}{V_{step-1}}+(1-\beta_2){\cdot}g_t^2 Vt=β2Vstep1+(1β2)gt2

修正二階動量偏差: v t ^ = v t 1 − β 2 t \hat{v_t}=\frac{v_t}{1-{\beta_2^t}} vt^=1β2tvt

η t = l r ⋅ m t ^ / v t ^ = l r ⋅ m t 1 − β 1 t / v t 1 − β 2 t \eta_t = {lr}\cdot{{\hat{m_t}}}/{\sqrt{\hat{v_t}}}=lr{\cdot}{\frac{m_t}{1-{\beta_1^t}}}/{\frac{v_t}{1-{\beta_2^t}}} ηt=lrmt^/vt^ =lr1β1tmt/1β2tvt

相關文章