基礎理解
看到梯度下降算法,首先我們應該去了解幾個問題,這是什麼?幹什麼用的?爲什麼會產生這個概念或者事物?實現的具體思路是什麼?爲什麼這麼實現,其背後的原理是什麼?
首先我們應該明確的一點是,所謂的梯度下降算法並不是一個機器學習算法,而是一個基於搜索的最優化算法。我們在上一節所講到的線性迴歸算法的目標是最優化一個損失函數,這也是梯度下降算法的思路。而梯度上升算法是最大化一個效用函數。
其次我們需要明確,爲什麼會產生這種算法呢?從上一節我們可以看出來,我們可以通過正規方程解的方式求解出theta的值,但是很多數情況下theta的值是沒法求出其具體的公式的,因此梯度下降算法應允而生。
實現的具體思路及邏輯:
要實現梯度下降,要就是實現最小化一個損失函數,需要用到導數,參數爲theta,對theta進行求解導數,需要不斷的遞減theta然後進行求解,此時便用到了學習速率。
而且學習速率取值的大小也十分的重要。
如圖所示:
梯度下降算法在線性迴歸中的使用:
公式推導:
代碼封裝:
def fit_gd(self,X_train,y_train,eta=0.01,n_iters=1e4):
'''check'''
assert X_train.shape[0] == y_train.shape[0],\
"the size must be valid"
'''No.1 get J'''
def J(X_b,theta,y):
try:
return np.sum(y - X_b.dot(theta)) / len(y)
except:
return float('inf')
def DJ(X_b,theta,y):
return X_b.T.dot(X_b.dot(theta) - y) *2 / len(X_b)
def gradient_decent(X_b,y,initial_theta,eta,n_iters = 1e4,epsilon = 1e-8):
theta = initial_theta
cur_iters = 0
while cur_iters < n_iters:
gradient = DJ(X_b,y,theta)
last_theta = theta
theta = theta - gradient*n_iters
if(abs(J(X_b,y,theta) - J(X_b,y,last_theta)) < epsilon):
break
cur_iters += 1
X_b = np.hstack([np.ones((len(X_train),1)),X_train])
initial_theta = np.zeros(X_b.shape[1])
self._theta = gradient_decent(X_b,y_train,initial_theta,eta,n_iters)
self.coef_ = self._theta[1:]
self.interception_ = self._theta[0]
return self
隨機梯度下降法
隨機梯度下降法和批量梯度下降法在計算theta時是兩種不同的方式,兩者互有千秋,將兩者正式融合的是小批量梯度下降法(代碼會在GitHub中開源,博客不會詳細介紹)。
現在介紹兩者區別:
批量梯度下降法(Batch Gradient Descent):是梯度下降的最原始的一種方式,使用特點和思路是使用全部的樣本進行更新theta,這樣的做法效率很低,訓練過程慢。
隨機梯度下降法:和BGD不同,隨機梯度下降法在更新theta時使用的是隨機的一個樣本進行更新,例如如果存在10萬條數據,我們使用幾萬條數據便將theta更新到最優解了,大大提升了訓練模型的效率,但是準確率較低。(通常情況下,我們願意使用犧牲模型一定的精度來換取訓練模型所用的時間)。
另外,實現隨機梯度下降時所用的學習速率需要注意:
我們每次都是採取的隨機的一個樣本,如果採用固定的學習速率的話,如果我們接近找到的最佳的theta,就會慢慢的跳出最優位置,解決方案是需要讓學習速率根據運行的次數越來越小。
模擬退火的思想,我們將學習速率定義爲下面的函數:
經驗上比較適合的值:a = 5、b = 50;
封裝隨機梯度下降算法
def fit_sgd(self,X_train,y_train,eta=0.01,n_iters=5,t0=5,t1=50):
'''check'''
assert X_train.shape[0] == y_train.shape[0],\
"the size must be valid"
assert n_iters>=1,\
"the valud must be >= 1"
def dJ_sgd(theta,x_b_i,y_i):
return x_b_i*(x_b_i.dot(theta) - y_i) * 2.
def sgd(X_b,y,initial_theta,n_iters,t0=5,t1=50):
def learning_rate(t):
return t0 / (t + t1)
theta = initial_theta
m = len(X_b)
for cur_iters in range(n_iters):
indexes = np.random.permutation(m)
X_b_new = X_b[indexes]
y_train_new = y_train[indexes]
for i in range(m):
gradient = dJ_sgd(theta,X_b_new[i],y_train_new[i])
theta = theta - eta * gradient
return theta
X_b = np.hstack([np.ones((len(X_train), 1)), X_train])
initial_theta = np.zeros(X_b.shape[1])
self._theta = sgd(X_b, y_train, initial_theta, eta, n_iters)
self.coef_ = self._theta[1:]
self.interception_ = self._theta[0]
return self
後一小節將介紹小批量梯度下降算法和對梯度下降算法的更多思考