機器學習筆記(八)——隨機梯度上升(下降)算法調優

前言概述

上一篇文章對邏輯迴歸的原理和基本思想做了一些簡要介紹,並通過引入Sigmoid函數和梯度公式成功推導出了梯度上升和梯度下降公式,上文分類實例是依據全批量提升上升法,而本文會介紹全批量梯度上升的一種優化算法——隨機梯度上升,如果還未懂得邏輯迴歸思想和推理公式的原理,還請觀看上一篇文章:機器學習筆記(七)——初識邏輯迴歸、不同方法推導梯度公式。

隨機梯度上升

區別對比

在講解全批量梯度上升和隨機梯度上升的區別之前,先看一下二者的公式之間的對比,有助於之後的理解。
全批量梯度上升法:
在這裏插入圖片描述
隨機梯度上升法:
在這裏插入圖片描述
全批量梯度上升公式我們已經很熟悉,在上一篇文章有介紹;其實隨機梯度上升與全批量的公式十分相似,原理也是大致相同的,不同點體現在何處呢?全批量在每次更新迴歸係數時都需要遍歷整個數據集,這種方法在處理小數據集時尚可,但如果有數十億樣本和成千上萬的特徵,那麼該方法的計算複雜度太高。而隨機梯度上升是一次僅用一個樣本點來更新迴歸係數,這樣做大大減小了計算複雜度,並且提高了函數的收斂速度。

更改算法

隨機梯度上升算法僞代碼如下

所有迴歸係數初始化爲1
對數據集中每個樣本
      計算該樣本的梯度
      使用alpha*gradient更新迴歸係數值
返回迴歸係數值

因爲兩個公式大體上一致,所以隨機梯度上升法的代碼只會稍微有些出入。

def stocGradAscent1(dataMatrix, classLabels):
    #將列表轉化爲array格式
    dataMatrix = np.array(dataMatrix)
    # 獲取dataMatrix的行、列數
    m,n = np.shape(dataMatrix)
    # 初始化迴歸係數和步長
    weights = np.ones(n)
    alpha = 0.01
    for i in range(m):
        # 遍歷樣本,每次選出一個,計算h
        h = sigmoid(sum(dataMatrix[i]*weights))
        # 計算誤差
        error = classLabels[i] - h
        # 更新迴歸係數
        weights = weights + alpha * error * dataMatrix[i]
    return weights

可以看到兩種算法有些區別:第一,隨機梯度上升的變量h和誤差error都是數值,而全批量中二者都是向量格式;第二,隨機梯度沒有矩陣運算,所有變量的數據類型都爲Numpy數組。

執行上述代碼可以得到一條新的最佳擬合直線圖,如下:
在這裏插入圖片描述
可以看到,這條新的最佳擬合直線只分對了二分之一的樣本。明明是對算法進行調優,可是準確率怎麼越調越低呢?
在這裏插入圖片描述
原因是全批量梯度上升法是在整個數據集上迭代了500次纔得到的,迭代次數要遠大於隨機梯度方法,而判斷一個算法優劣的可靠方法是看它是否收斂,也就是參數是否達到了穩定值,是否還會不斷變化。

下圖爲兩種方法迭代次數與迴歸係數之間的關係:

可以看到全批量梯度三個迴歸圖像與隨機梯度相比波動幅度都比較大,用最明顯的迴歸係數X2作比較,前者在下標爲300時收斂完成,而後者在下標14000時曲線才近乎平穩;但這裏需要注意的是,全批量梯度每次迭代都是利用整個數據集,所以該方法收斂完成時的準確迭代次數應該是30000次,比隨機梯度的迭代次數要多的多。

隨機梯度方法在大的波動之後,還有很多小的週期波動,產生這種現象的原因是存在一些不能正確分類的樣本點,在每次迭代時會引發係數的劇烈改變。我們希望算法可以避免波動問題,從而收斂到某個值,並且加快收斂速度。

算法調優

所以對隨機梯度上升算法做以下改進:

def stocGradAscent2(dataMatrix, classLabels, numIter=150):
    #將列表轉化爲array格式
    dataMatrix = np.array(dataMatrix)
    # 獲取dataMatrix的行、列數
    m,n = np.shape(dataMatrix)
    # 初始化迴歸係數和步長
    weights = np.ones(n)
    for j in range(numIter):
        dataIndex = list(range(m))
        for i in range(m):
            # 逐漸減小alpha,每次減小量爲1.0/(j+i)
            1、alpha = 4/(1.0+j+i)+0.01
            # 隨機選取樣本
            2、randIndex = int(random.uniform(0,len(dataIndex)))
            # 隨機選取的一個樣本,計算h
            h = sigmoid(sum(dataMatrix[randIndex]*weights))
            # 計算誤差
            error = classLabels[randIndex] - h
            # 更新迴歸係數
            weights = weights + alpha * error * dataMatrix[randIndex]
            # 刪除已經使用過的樣本
            del(dataIndex[randIndex])
    return weights

第一處改進目的在於每一次迭代都會調整步長alpha的值,alpha每次迭代都會減小1/(j+i),其中j是迭代次數,i是樣本點的下標。雖然alpha會隨着迭代次數不斷減小,但永遠不會減小到0,其中還存在一個常數項,這是因爲在多次迭代之後alpha的值近乎爲0,這樣新數據對於迴歸係數的更新幾乎沒有作用。

這裏再利用圖片再講解一下爲什麼要這樣優化alpha。
在這裏插入圖片描述
上圖是一個二次函數的圖像,在最開始時梯度較大,步長alpha可以比較大,但梯度是呈現逐漸減小趨勢的,這時離最優值也越來越近,步長alpha也要隨之減小。如果下降速率很大,在接近最優點時,梯度乘以了一個數值比較大的alpha,就會出現下圖這類情況。
在這裏插入圖片描述
例如從點1直接跳到了點2,開始震盪,上述迭代次數與迴歸係數關係圖中的較大震盪產生的原因,而上述對步長alpha的優化即可避免這類情況,雖然舉例用的是梯度下降,但梯度上升和梯度下降的原理是一致的。

第二處改進的目的是減少隨機梯度關係圖中週期性的波動,這裏通過隨機選取抽樣樣本更新迴歸係數,每次隨機從列表中選取一個值,然後從列表中刪掉該值,再進行下一次迭代,與決策樹選取信息增益的方式類似。

下圖給出了改進後的隨機梯度上升法迭代次數與迴歸係數的關係圖。

可以看出這種方法三個迴歸係數圖像比固定步長alpha的方法收斂速度都要快,並且沒有了週期性的波動,爲了更直觀地看到改進算法的效果,下圖給出了利用改進後的算法繪製出的最佳擬合直線圖。
在這裏插入圖片描述
最終隨機梯度的分類效果與全批量梯度幾乎一樣,但是迭代次數卻要少很多很多,所以前者很大程度上降低了算法的計算複雜度,減小了程序使用的內存。

總結

文末總結一下全批量梯度下降法、隨機梯度下降法、小批量梯度下降法的優缺點即適應場合。

全批量梯度下降法(BGD):每次更新迴歸係數所有樣本都參與。

  • 優點:分類準確,獲取全局最優解
  • 缺點:當樣本比較多時,訓練速度特別慢
  • 適用場合:樣本較少的數據集

隨機梯度下降法(SGD):每次更新迴歸係數只有一個樣本參與。

  • 優點:訓練速度很快
  • 缺點:準確率會降低,並不是朝着整體最優方向進行,容易獲取到局部最優解
  • 適用場合:樣本非常多的數據集

小批量梯度下降法(MBGD):每次更新迴歸係數有一部分樣本參與。這種方法兼顧了上述兩種方法的優點,同時也減弱了兩者的缺點,算是兩種前兩種算法的一種平衡。如果數據集的樣本數不是很極端,最好採用小批量梯度下降法。

關注公衆號【奶糖貓】後臺回覆“隨機梯度”可獲取源碼供參考,感謝閱讀。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章