1. 程式人生 > >梯度下降的三種形式

梯度下降的三種形式

梯度下降法的三種形式BGD、SGD以及MBGD

轉自:https://zhuanlan.zhihu.com/p/25765735

在應用機器學習演算法時,我們通常採用梯度下降法來對採用的演算法進行訓練。其實,常用的梯度下降法還具體包含有三種不同的形式,它們也各自有著不同的優缺點。

下面我們以線性迴歸演算法來對三種梯度下降法進行比較。

一般線性迴歸函式的假設函式為:

 

對應的損失函式為:

 

這裡的1/2是為了後面求導計算方便
下圖作為一個二維引數(\theta _{0}\theta _{1}組對應能量函式的視覺化圖

 

下面我們來分別講解三種梯度下降法

批量梯度下降法BGD

我們的目的是要誤差函式儘可能的小,即求解weights使誤差函式儘可能小。首先,我們隨機初始化weigths,然後不斷反覆的更新weights使得誤差函式減小,直到滿足要求時停止。這裡更新演算法我們選擇梯度下降演算法,利用初始化的weights並且反覆更新weights:

 

這裡\alpha代表學習率,表示每次向著J最陡峭的方向邁步的大小。為了更新weights,我們需要求出函式J的偏導數。首先當我們只有一個數據點(x,y)的時候,J的偏導數是:

 

則對所有資料點,上述損失函式的偏導(累和)為:

 

再最小化損失函式的過程中,需要

不斷反覆的更新weights使得誤差函式減小,更新過程如下:

 

那麼好了,每次引數更新的虛擬碼如下:

 

由上圖更新公式我們就可以看到,我們每一次的引數更新都用到了所有的訓練資料(比如有m個,就用到了m個),如果訓練資料非常多的話,是非常耗時的。

下面給出批梯度下降的收斂圖:

從圖中,我們可以得到BGD迭代的次數相對較少。

隨機梯度下降法SGD

由於批梯度下降每跟新一個引數的時候,要用到所有的樣本數,所以訓練速度會隨著樣本數量的增加而變得非常緩慢。隨機梯度下降正是為了解決這個辦法而提出的。它是利用每個樣本的損失函式對θ求偏導得到對應的梯度,來更新θ:

 

更新過程如下:

 

隨機梯度下降是通過每個樣本來迭代更新一次,對比上面的批量梯度下降,迭代一次需要用到所有訓練樣本(往往如今真實問題訓練資料都是非常巨大),一次迭代不可能最優,如果迭代10次的話就需要遍歷訓練樣本10次。但是,SGD伴隨的一個問題是噪音較BGD要多,使得SGD並不是每次迭代都向著整體最優化方向。

隨機梯度下降收斂圖如下:

我們可以從圖中看出SGD迭代的次數較多,在解空間的搜尋過程看起來很盲目。但是大體上是往著最優值方向移動。

min-batch 小批量梯度下降法MBGD

我們從上面兩種梯度下降法可以看出,其各自均有優缺點,那麼能不能在兩種方法的效能之間取得一個折衷呢?即,演算法的訓練過程比較快,而且也要保證最終引數訓練的準確率,而這正是小批量梯度下降法(Mini-batch Gradient Descent,簡稱MBGD)的初衷。

我們假設每次更新引數的時候用到的樣本數為10個(不同的任務完全不同,這裡舉一個例子而已

更新虛擬碼如下:

 

例項以及程式碼詳解

這裡參考他人部落格,建立了一個數據,如下圖所示:

 

待訓練資料A、B為自變數,C為因變數。

我希望通過這些訓練資料給我訓練出一個線性模型,用於進行下面資料的預測,test集合如下:

 

比如我們給出(3.1,5.5)希望模型預測出來的值與我們給定的9.5的差別是多少?這不是重點,重點是我們訓練模型過程中的引數更新方法(這是我們這篇文章的重點)批梯度下降以及隨機梯度下降程式碼如何實現。下面分別來講:

首先我們看批梯度下降法的程式碼如下:

這裡有可能還是比如抽象,為了讓大家更好的弄懂理解這倆個重要的方法,我下面結合例子,一行一行程式碼解釋:

我們看隨機梯度下降法的程式碼如下:

與批梯度下降最大的區別就在於,我們這裡更新引數的時候,並沒有將所有訓練樣本考慮進去,然後求和除以總數,而是我自己程式設計實現任取一個樣本點程式碼中random函式就能清楚看到),然後利用這個樣本點進行更新!這就是最大的區別!

那麼到這個時候,我們也非常容易知道小批量隨機梯度下降法的實現就是在這個的基礎上,隨機取batch個樣本,而不是1個樣本即可,掌握了本質就非常容易實現!

下面給出這個線性模型所有程式碼,訓練,預測以及結果供參考:

複製程式碼

 1 #coding=utf-8
 2 import numpy as np
 3 import random
 4 
 5 #下面實現的是批量梯度下降法
 6 def batchGradientDescent(x, y, theta, alpha, m, maxIterations):
 7     xTrains = x.transpose()                             #得到它的轉置
 8     for i in range(0, maxIterations):
 9         hypothesis = np.dot(x, theta)
10         loss = hypothesis - y
11         # print loss
12         gradient = np.dot(xTrains, loss) / m             #對所有的樣本進行求和,然後除以樣本數
13         theta = theta - alpha * gradient
14     return theta
15 
16 #下面實現的是隨機梯度下降法
17 def StochasticGradientDescent(x, y, theta, alpha, m, maxIterations):
18     data = []
19     for i in range(10):
20         data.append(i)
21     xTrains = x.transpose()     #變成3*10,沒一列代表一個訓練樣本
22     # 這裡隨機挑選一個進行更新點進行即可(不用像上面一樣全部考慮)
23     for i in range(0,maxIterations):
24         hypothesis = np.dot(x, theta)
25         loss = hypothesis - y                   #注意這裡有10個樣本的,我下面隨機抽取一個進行更新即可
26         index = random.sample(data,1)           #任意選取一個樣本點,得到它的下標,便於下面找到xTrains的對應列
27         index1 = index[0]                       #因為回來的時候是list,我要取出變成int,更好解釋
28         gradient = loss[index1]*x[index1]       #只取這一個點進行更新計算
29         theta = theta - alpha * gradient.T
30     return theta
31 
32 def predict(x, theta):
33     m, n = np.shape(x)
34     xTest = np.ones((m, n+1))                     #在這個例子中,是第三列放1
35     xTest[:, :-1] = x                             #前倆列與x相同
36     res = np.dot(xTest, theta)                    #預測這個結果
37     return res
38 
39 trainData = np.array([[1.1,1.5,1],[1.3,1.9,1],[1.5,2.3,1],[1.7,2.7,1],[1.9,3.1,1],[2.1,3.5,1],[2.3,3.9,1],[2.5,4.3,1],[2.7,4.7,1],[2.9,5.1,1]])
40 trainLabel = np.array([2.5,3.2,3.9,4.6,5.3,6,6.7,7.4,8.1,8.8])
41 m, n = np.shape(trainData)
42 theta = np.ones(n)
43 alpha = 0.1
44 maxIteration = 5000
45 #下面返回的theta就是學到的theta
46 theta = batchGradientDescent(trainData, trainLabel, theta, alpha, m, maxIteration)
47 print "theta = ",theta
48 x = np.array([[3.1, 5.5], [3.3, 5.9], [3.5, 6.3], [3.7, 6.7], [3.9, 7.1]])
49 print predict(x, theta)
50 theta = StochasticGradientDescent(trainData, trainLabel, theta, alpha, m, maxIteration)
51 print "theta = ",theta
52 x = np.array([[3.1, 5.5], [3.3, 5.9], [3.5, 6.3], [3.7, 6.7], [3.9, 7.1]])
53 print predict(x, theta)
54 #yes,is the code

複製程式碼

最後執行結果為:

 

說明與我們給定的真實值是完全對應的。

三種梯度下降方法的總結

1.批梯度下降每次更新使用了所有的訓練資料,最小化損失函式,如果只有一個極小值,那麼批梯度下降是考慮了訓練集所有資料,是朝著最小值迭代運動的,但是缺點是如果樣本值很大的話,更新速度會很慢。

2.隨機梯度下降在每次更新的時候,只考慮了一個樣本點,這樣會大大加快訓練資料,也恰好是批梯度下降的缺點,但是有可能由於訓練資料的噪聲點較多,那麼每一次利用噪聲點進行更新的過程中,就不一定是朝著極小值方向更新,但是由於更新多輪,整體方向還是大致朝著極小值方向更新,又提高了速度。

3.小批量梯度下降法是為了解決批梯度下降法的訓練速度慢,以及隨機梯度下降法的準確性綜合而來,但是這裡注意,不同問題的batch是不一樣的,聽師兄跟我說,我們nlp的parser訓練部分batch一般就設定為10000,那麼為什麼是10000呢,我覺得這就和每一個問題中神經網路需要設定多少層,沒有一個人能夠準確答出,只能通過實驗結果來進行超引數的調整。

好了,本篇文章要講的已經講完了,真心希望對大家理解有幫助,歡迎大家指錯交流!

參考:

梯度下降演算法以及其Python實現