如何確定梯度計算的准確性以及調試梯度下降法
如何調試梯度
關於梯度的調試的方法的思想
對於一根曲線,我們求其在某一個點的相應的梯度值,我們就要求這個導數值,那么這個導數對應的就是這個點上的相切的直線的斜率,那么我們可以試着模擬這個直線的斜率,方式是在這個點的正方向的附近取一個點,在負方向上同樣的也取一個點,那么我們就說這兩點的連線的斜率和我們在這個點的切線的斜率是大致相同的,這個間距越小,越接近相同,思想類似於導數的定義,在很小的時候取一個極限,那么我們就能將這個直線的斜率算出來,作為這個切線的取代值,那么我們就得到了模擬計算斜率的式子
這個模擬也是適合高維的場景,如果theta是個n維向量,那么我們想要求出theta對應的梯度的話,我們就要使這個函數對theta中的每一個分量進行求導,那么對每一個分量去求導,以此類推,這樣我們就可以得到梯度,但是這是很麻煩的,這僅僅作為是個調試手段,使用小數據量來進行結果的推導
(在notebook中)
同樣的將需要的加載好,X的樣本數為1000,我們設置成有十個維度,我們先設置好真的theta值,這里設置十一個數,有了真的theta值以后,我們先求出來對應的X_b,之后如果真的在x和y之間有線性關系並且是被true_theta給划了的話,那么就使y為X_b.dot(true_theta),同時加上一個噪音
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(666)
X =np.random.random(size=(1000,10))
true_theta = np.arange(1,12,dtype=float)
X_b = np.hstack([np.ones((len(X),1)),X])
y = X_b.dot(true_theta) + np.random.normal(size=1000)
其中X.shape為
相應的y.shape為
其中的true_theta為
首先我們先設置一個函數,這個函數可以求解出相應損失函數
def J(theta, X_b, y):
try:
return np.sum((y - X_b.dot(theta)) ** 2) / len(X_b)
except:
return float('inf')
然后在使用數學推導的方式來求梯度
def dJ_math(theta, X_b, y):
return X_b.T.dot(X_b.dot(theta) - y) * 2. / len(y)
相應的,設置一個調試方式來求梯度,因為返回的是一個等長的向量,因此設置成len(theta),然后進行循環,每一次求梯度的一個維度的對應的值,我們取兩個值,最后進行計算即可得相應的值,返回對應的點的導數值
def dJ_debug(theta,X_b,y,epsilon=0.01):
res = np.empty(len(theta))
for i in range(len(theta)):
theta_1 = theta.copy()
theta_1[i] += epsilon
theta_2 = theta.copy()
theta_2[i] -= epsilon
res[i] = (J(theta_1,X_b,y) - J(theta_2,X_b,y)) / (2*epsilon)
return res
使用批量梯度下降法來進行驗證
def gradient_descent(dJ,X_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8):
theta = initial_theta
cur_iter = 0
while cur_iter < n_iters:
gradient = dJ(theta, X_b, y)
last_theta = theta
theta = theta - eta * gradient
if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):
break
cur_iter += 1
return theta
要想使用,首先要先得出X_b,其次在取全0的theta值,學習率為0.01,然后就可以調用了,首先我們使用調試的方法,得出結果並計時
X_b = np.hstack([np.ones((len(X),1)),X])
initial_theta = np.zeros(X_b.shape[1])
eta = 0.01
%time theta = gradient_descent(dJ_debug,X_b,y,initial_theta,eta)
Theta
結果如下
使用數學推導的方法並計時
%time theta = gradient_descent(dJ_math,X_b,y,initial_theta,eta)
theta
結果如下
這說明了兩件事
第一件事是使用debug的方法來求梯度是可以的,最終是可以得到結果
第二件事就是使用這種方法來進行求值的話,會慢很多
因此在遇到含有梯度的求法的機器學習算法的時候,我們完全可以先使用debug的方法來作為梯度的算法,通過這個方式,我們可以先得到我們想要的正確的結果,然后我們再來推導公式,來計算這個相應的數學解
之后我們將數學解帶入到算法中,通過使用的的結果來對比debug的結果,看看是否一樣,來驗證我們推導的數學解是否是正確的,debug函數是基於當前的函數來debug的,可以不用看J的情況,所以很多時候我們都可以使用這個方法
關於梯度下降法的更多以及總結
批量梯度下降法是每一次都要對所有的樣本看一遍才能求出梯度,相對來講,這個方法每一次會比較慢,但是很穩定,一定向着損失函數下降最快的方向進行前進
隨機梯度下降法是每一次只用看一個樣本就可以求出相應的梯度,相對來講,雖然這個方法很快,但是不穩定,每一次的方向都是不確定的,甚至有可能反方向前進
綜合二者的優缺點,我們就可以得到小批量梯度下降法,什么是小批量呢,我們每一次都不要看所有的樣本,但是也不能只看一個樣本,我們每次只看k個樣本,這樣既提升了速度有上升了精度,其中的梯度推導的思想和上面是一樣的,只是多了一個超參數k
隨機在機器學習的領域是十分重要的,對於一個復雜的函數來說,它可以通過隨機的方式來跳出局部最優解,同時可以獲取到更快的運行速度,機器學習領域很多的算法都會使用隨機的特點,例如隨機搜索,隨機森林算法,蒙特卡洛樹等,由於機器學習本身就是解決在不確定的世界中不確定的問題,其本身很有可能就沒有一個固定的最優解,因此,隨機是很重要的