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

前言概述

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

隨機梯度上升

區別對比

在講解全批量梯度上升和隨機梯度上升的區別以前,先看一下兩者的公式之間的對比,有助於以後的理解。算法

全批量梯度上升法:segmentfault

隨機梯度上升法:數組

全批量梯度上升公式咱們已經很熟悉了,上一篇文章有介紹;其實隨機梯度上升與全批量的公式十分類似,原理也是大體相同的,不一樣點體如今何處呢?全批量在每次更新迴歸係數時都須要遍歷整個數據集,這種方法在處理小數據集時尚可,但若是有數十億樣本和成千上萬的特徵,那麼該方法的計算複雜度過高。而隨機梯度上升是一次僅用一個樣本點來更新迴歸係數,這樣作大大減少了計算複雜度,而且提升了函數的收斂速度。dom

更改算法

隨機梯度上升算法僞代碼以下機器學習

全部迴歸係數初始化爲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數組。學習

執行上述代碼能夠獲得一條新的最佳擬合直線圖,以下:優化

能夠看到,這條新的最佳擬合直線只分對了二分之一的樣本。明明是對算法進行調優,但是準確率怎麼越調越低呢?spa

緣由是全批量梯度上升法是在整個數據集上迭代了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)
            一、alpha = 4/(1.0+j+i)+0.01
            # 隨機選取樣本
            二、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):每次更新迴歸係數有一部分樣本參與。這種方法兼顧了上述兩種方法的優勢,同時也減弱了二者的缺點,算是兩種前兩種算法的一種平衡。若是數據集的樣本數不是很極端,最好採用小批量梯度降低法。

關注公衆號【奶糖貓】後臺回覆「隨機梯度」可獲取源碼供參考,感謝閱讀。
相關文章
相關標籤/搜索