1. 程式人生 > >機器學習演算法的除錯 —— 梯度檢驗(Gradient Checking)

機器學習演算法的除錯 —— 梯度檢驗(Gradient Checking)

反向傳播演算法很難除錯得到正確結果,尤其是當實現程式存在很多難於發現的bug 時。舉例來說,索引的缺位錯誤(off-by-one error)會導致只有部分層的權重得到訓練(for(i=1; i<=m; ++i) 被漏寫為 for(i=1; i<m; ++i)),再比如忘記計算偏置項。這些錯誤會使你得到一個看似十分合理的結果(但實際上比正確程式碼的結果要差)。因此,僅從計算結果上來看,我們很難發現程式碼中有什麼東西遺漏了。本節中,我們將介紹一種對求導結果進行數值檢驗的方法,該方法可以驗證求導程式碼是否正確。另外,使用本節所述求導檢驗方法,可以幫助你提升寫正確程式碼的信心。

數學原理

考慮我們想要最小化以 θ 為自變數的目標函式 J(θ)θ 可以為標量和可以為向量,在 Numpy 的程式設計環境下,處理是一樣的),迭代梯度更新公式為:

θ:=θαddθJ(θ)
我們不妨以 Sigmoid 函式為例,也即 f(z)=11+exp(z),其導數形式為 f(z)=g(z)=f(z)(1f(z)),我們可輕易地程式設計實踐,接著我們便可使用 θ:=θαddθJ(θ)來實現梯度下降演算法,那麼我們如何知道 g(z)梯度的正確性呢。

回憶導數的數學定義:

ddθJ=limϵ0J(θ+ϵ)J(θϵ)2ϵ

由此我們可得梯度校驗的數值校驗公式:

g(θ
)J(θ+ϵ)J(θϵ)2ϵ

這便是梯度檢驗的原理。在實際應用中,我們常將 ϵ 設為一個很小的常量,比如 104 數量級,我們不會將它設得太小,比如 1020,因為那將導致數值舍入誤差。 事實上,上式兩端值的接近程度取決於 J 的具體形式,但在假定 ϵ=104 的情況 下,通常會發現左右兩端至少有四位有效數字是一致的(或者說精度至少在0.0001一級)。

程式設計實現

import numpy as np

def sigmoid(z):
    return 1./(1+np.exp(-z))
def sigmoid_prime(z):
    return sigmoid(z)*(1
-sigmoid(z)) def check_gradient(f, x0, epsilon): return (f(x0+epsilon) - f(x0-epsilon))/2/epsilon if __name__ == '__main__': x0 = np.array([1, 2, 3]) epsilon = 1e-4 print(sigmoid_prime(x0)) # [ 0.19661193 0.10499359 0.04517666] print(check_gradient(sigmoid, x0, epsilon)) # [ 0.19661193 0.10499359 0.04517666]

References