線性迴歸之梯度下降算法

線性迴歸之梯度下降法

1.梯度的概念

梯度是一個向量,對於一個多元函數\(f\)而言,\(f\)在點\(P(x,y)\)的梯度是\(f\)在點\(P\)處增大最快的方向,即以f在P上的偏導數爲分量的向量。以二元函數\(f(x,y)\)爲例,向量\(\{\frac{\partial f}{\partial x},\frac{\partial f}{\partial y}\}|_{(x_0,y_0)}=f_x(x_0,y_0)\overrightarrow i+f_y(x_0,y_0)\overrightarrow j\)就是函數\(f(x,y)\)在點\(P(x_0,y_0)\)處的梯度,記作\(gradf(x,y)\)或者\(\nabla f(x,y)\)

2.梯度下降法

對於梯度下降,我們可以形象地理解爲一個人下山的過程。假設現在有一個人在山上,現在他想要走下山,但是他不知道山底在哪個方向,怎麼辦呢?顯然我們可以想到的是,一定要沿着山高度下降的地方走,不然就不是下山而是上山了。山高度下降的方向有很多,選哪個方向呢?這個人比較有冒險精神,他選擇最陡峭的方向,即山高度下降最快的方向。現在確定了方向,就要開始下山了。又有一個問題來了,在下山的過程中,最開始選定的方向並不總是高度下降最快的地方。這個人比較聰明,他每次都選定一段距離,每走一段距離之後,就重新確定當前所在位置的高度下降最快的地方。這樣,這個人每次下山的方向都可以近似看作是每個距離段內高度下降最快的地方。現在我們將這個思想引入線性迴歸,在線性迴歸中,我們要找到參數矩陣\(\theta\)使得損失函數\(J(\theta)\)最小。如果把損失函數\(J(\theta)\)看作是這座山,山底不就是損失函數最小的地方嗎,那我們求解參數矩陣\(\theta\)的過程,就是人走到山底的過程。

image-20191105211435202

如圖所示,這是一元線性迴歸(即假設函數\(h_\theta(x) = \theta_0+\theta_1x\))中的損失函數圖像,一開始我們選定一個起始點(通常是\((\theta_0=0,\theta_1=0)\)),然後沿着這個起始點開始,沿着這一點處損失函數下降最快的方向(即該點的梯度負方向)走一小步,走完一步之後,到達第二個點,然後我們又沿着第二個點的梯度負方向走一小步,到達第三個點,以此類推,直到我們到底局部最低點。爲什麼是局部最低點呢?因爲我們到達的這個點的梯度爲0向量(通常是和0向量相差在某一個可接受的範圍內),這說明這個點是損失函數的極小值點,並不一定是最小值點。

image-20191105212707135

從梯度下降法的思想,我們可以看到,最後得到的局部最低點與我們選定的起始點有關。通常情況下,如果起始點不同,最後得到的局部最低點也會不一樣。

3.梯度下降算法描述

現在對於梯度下降法,有了一個直觀形象的理解了。接下來,我們看一下梯度下降算法。首先,我們給在下山的例子中每一段路的距離取名叫學習率(Learning Rate,也稱步長,用\(\alpha\)表示),把一次下山走一段距離叫做一次迭代。算法詳細過程:

  1. 確定定參數的初始值,計算損失函數的偏導數

  2. 將參數代入偏導數計算出梯度。若梯度爲0,結束;否則轉到3

  3. 用步長乘以梯度,並對參數進行更新
  4. 重複2-3

對於多元線性迴歸來說,擬合函數爲:

\[h_\theta(x) = \sum_\limits{i=0}^n\theta_ix_i =\theta_0+ \theta_1x_1 + \cdots+\theta_nx_n \tag{3.1}\]

損失函數爲:

\[J(\theta)=\frac{1}{2m}\sum_\limits{i=0}^m(y^{(i)}-h_\theta(x^{(i)}))^2 \tag{3.2}\]

損失函數的偏導數爲:

\[\frac{\partial J(\theta)}{\theta_i} = \frac{1}{m}\sum_\limits{j=1}^m(h_\theta(x^{(j)})-y^{(j)})x_i^{(j)}=\frac{1}{m}\sum_\limits{j=1}^m(\sum_\limits{i=0}^n\theta_ix_i^{(j)}-y^{(j)})x_i^{(j)}\quad (i=0,1,\dots,n) \tag{3.3}\]

每次更新參數的操作爲:

\[\theta_i = \theta_i-\alpha\frac{\partial J(\theta)}{\theta_i} = \theta_i-\alpha\frac{1}{m}\sum_\limits{j=1}^m(h_\theta(x^{(j)})-y^{(j)})x_i^{(j)}\quad (i=0,1,\dots,n)\tag{3.4}\]

注意,更新參數時必須同步更新所有參數,不能先更新\(\theta_0\)再更新\(\theta_1\),如果用Java僞代碼就是:

double []temp = new double[n+1]; //因爲參數𝜃從𝜃0到𝜃𝑛,所以一共n+1,temp數組表示每次下降的高度
for(int i = 0; i < temp.length();i++){  
  double sum = 0;
  for(int j = 0; j < m; j++){
    double hx = 0;
    for(int k = 0; k <= n; k++){
        hx += theta[k]*x[j][k];
    }
    sum += (hx - y[j])*x[j][i];
  }
  temp[i] = alpha/m*sum;    
}
for(int i = 0; i < n; i++)
  theta[i] = theta[i] -temp[i];

對於這種需要同步更新的,最好的方法是採用矩陣運算,Java代碼是(採用commons-math3庫):

theta = (theta.substract(alpha/m*(X.transpose().multiply(X.multiply(theta)-y))).copy;
//theta爲(n+1)*1維,X爲m*(n+1)維,y爲m*1維

數學推導如下:

\[h_\theta(x) = \theta^Tx,J(\theta) = \frac{1}{2m}(X\theta-Y)^T(X\theta-Y),\frac{\partial J(\theta)}{\partial\theta}=\frac{1}{m}X^T(X\theta-Y),\theta = \theta - \alpha\frac{1}{m} X^T(X\theta-Y)\]

其中\(\theta\)爲(n+1)*1維,\(X\)爲m*(n+1)維,\(Y\)爲m*1維,\(x\)爲(n+1)*1維

4.特徵縮放

在梯度下降中,如果樣本的某些維度取值範圍並不合理,比如房價預測系統中將房價的單位採用萬億元/平方米,這樣每一個樣本值的房價會非常小,以至於在圖形表示時,幾乎是一條水平線,不同的擬合直線所計算出的損失函數之間的差值非常小。這樣採用直線取進行擬合時,如果我們在梯度下降法中循環結束的標誌是梯度值爲0,理論上這樣我們仍然可以計算出準確的參數值。但是通常情況下,我們採用的標誌是梯度與0相差在某一個可接受的範圍內,如果我們選定這個範圍是0.0001,0.0001乘以萬億,其結果是一億,這麼大的誤差顯然是不能接受的。所以,我們有必要進行特徵縮放,通常採用標準化的方式來進行特徵縮放,即\(x_i = \frac{x_i-\overline x_i}{\sigma_i}\)。特徵縮放之後,還可以加快我們的收斂速度。

5.其他梯度下降算法

在上文中,我們介紹了梯度下降法的思想和算法步驟,並給出了數學證明。實際上,文中介紹的是批量梯度下降法(Batch Gradient Descent, BSD)。梯度下降法,還有隨機梯度下降法(Stochastic Gradient Descent, SGD)和小批量梯度下降法(Mini-batch Gradient Descent, MBSD)。它們之間的區別僅在於更新參數\(\theta\)的方式不同,即採用全體樣本、隨機樣本或部分樣本。

6.學習率的選擇

在梯度下降算法中,迭代步長(即學習率)的選擇非常重要。如果步長太大,最後可能不收斂,即出現振盪。如果步長太小,那麼收斂速度太慢,我們需要很多次迭代來到達局部最優解。下圖是對於某一房價預測系統,選擇不同學習率時,損失函數隨迭代次數的變化:

可以看到在第一張圖片中,當\(\alpha=1.6\)時,迭代次數大於40之後,損失函數明顯越來越大。

image-20191106133240808

在第二張圖片中,當\(\alpha = 0.00001\)時,損失函數每一次迭代減少的非常小,收斂速度很慢,我們可能需要很多次迭代才能得到局部最優解。

有時候,在梯度下降算法中,學習率並不總是固定的,有時候也會依據梯度來改變學習率。

參考鏈接:

梯度下降小結

梯度下降法小結

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