優化算法-梯度下降法

梯度下降法是一個最優化算法,它採用迭代的方式,沿着負梯度方向(梯度的值的負方向)來小步長的搜尋最優解。當越接近最終的目標,它的搜索速度越慢。

求解方法

其迭代公式爲
  
,其中
  
代表梯度負方向,
  
表示梯度方向上的搜索步長。梯度方向我們可以通過對函數求導得到,步長的確定比較麻煩,太大了的話可能會發散,太小收斂速度又太慢。一般確定步長的方法是由線性搜索算法來確定,即把下一個點的座標ak+1看做是的函數,然後求滿足f(ak+1)的最小值的 即可。
因爲一般情況下,梯度向量爲0的話說明是到了一個極值點,此時梯度的幅值也爲0.而採用梯度下降算法進行最優化求解時,算法迭代的終止條件是梯度向量的幅值接近0即可,可以設置個非常小的常數閾值。

文章轉載

這幾天在看《統計學習方法》這本書,發現 梯度下降法 在 感知機 等機器學習算法中有很重要的應用,所以就特別查了些資料。   

 

   一.介紹

      梯度下降法(gradient descent)是求解無約束最優化問題的一種常用方法,有實現簡單的優點。梯度下降法是迭代算法,每一步需要求解目標函數的梯度向量。

 

   二.應用場景

     1.給定許多組數據(xi, yi),x(向量)爲輸入,yi爲輸出。設計一個線性函數y=h(x)去擬合這些數據。

     2.感知機:感知機(perceptron)爲二類分類的線性分類模型。 輸入爲實例的特徵向量,輸出爲實例的類別, 取+1 和 -1 二值。

 

     下面分別對這兩種應用場景進行分析。

     1.對於第一種場景:

        既然是線性函數,在此不妨設爲 h(x) = w0*x0 + w1*x1。

        此時我們遇到的問題就是如何確定w0和w1這兩個參數,即w=(w0,w1)這個向量。

        既然是擬合,則擬合效果可以用平方損失函數:E(w)=∑ [ h(x)- y ] ^2 / 2 來衡量。

        其中w是權重二維向量,x是輸入二維向量,x和y都是訓練集的數據,即已知。

        至於後面除於2只是爲了之後的推導過程中對E求導時候可以消除係數,暫時可以不管。

        因此該問題變成了求E(w)最小值的無約束最優化問題

      2.對於第二種場景:

        假設輸入空間(特徵向量)爲x,輸出空間爲y = {+1, -1},由輸入空間到輸出空間的如下函數

                        f(x) = sign(w · x + b)       w∈Rn     其中 w 叫做權值或者權值向量, b叫做偏振。w · x 表示向量w和x的點積

         感知機sign(w · x + b)的損失函數爲  L(w, b) = -∑yi(w · xi + b)              x ∈M, M爲誤分類點集合。

        因此該問題變成了求L(w, b)最小值的無約束最優化問題

 

   三.梯度下降方法

       梯度其實就是高數求導方法,對E這個公式針對每個維數(w0,w1)求偏導後的向量▽E(w)=(∂E/∂w0,∂E/∂w1)

       1. 對於第一種場景

          對E這個公式針對每個維數(w0,w1)求偏導後的向量▽E(w)=(∂E/∂w0,∂E/∂w1)

          梯度爲最陡峭上升的方向,對應的梯度下降的訓練法則爲: w=w-η▽E(w)     這裏的η代表學習速率,決定梯度下降搜索中的步長 。

          上式的w是向量,即可用將該式寫成分量形式爲:wi=wi-η*∂E/∂wi

          現在關鍵就使計算∂E/∂wi:

          推導過程很簡單,書上寫的很詳細,這裏只記錄結論(其實就是對目標函數求導):

          ∂E/∂wi=∑(h(x)-y)*(xi)

          這裏的∑是對樣本空間,即訓練集進行一次遍歷,耗費時間較大,可以使用梯度下降的隨機近似:

       2. 對於第二種場景

           感知機學習算法是誤分類驅動的,具體採用隨機梯度下降方法

           ▽wL(w, b) =   -∑yixi       

           ▽bL(w, b) =   -∑yi

           隨機選取一個誤分類點(xi,   yi), 對w, b進行更新:

            w  <——   w - η * (-yixi)

            b  <——    b - η * (-yi)                 式中η(0 < η <= 1)是步長,在統計學習中又稱爲學習率(learning rate)

  

   四.隨機梯度下降的隨機近似:

      既然是隨機近似,則顧名思義,肯定是用近似方法來改善梯度下降時候的時間複雜度問題。

      正如上所說,在∂E/∂wi=∑(h(x)-y)*(xi) 的時候∑耗費了大量的時間,特別是在訓練集龐大的時候。

      所以肯定有人會猜想,如果把求和去掉如何,即變爲∂E/∂wi=(h(x)-y)*(xi)。

      幸運的是,猜想成立了。

      只是要注意一下標準的梯度下降和隨機梯度下降的區別:

    1.標準下降時在權值更新前彙總所有樣例得到的標準梯度,隨機下降則是通過考察每次訓練實例來更新。

    2.對於步長 η的取值,標準梯度下降的η比隨機梯度下降的大。

    因爲標準梯度下降的是使用準確的梯度,理直氣壯地走,隨機梯度下降使用的是近似的梯度,就得小心翼翼地走,怕一不小心誤入歧途南轅北轍了。

    3.當E(w)有多個局部極小值時,隨機梯度反而更可能避免進入局部極小值中。

 四.代碼及實例:

  1. 對於第一種場景

         

複製代碼
 1 /*
 2  * 隨機梯度下降實驗:
 3  * 訓練集輸入爲矩陣:
 4  * 1,4
 5  * 2,5
 6  * 5,1
 7  * 4,2
 8  * 輸出結果爲:
 9  * 19
10  * 26
11  * 19
12  * 20
13  * 需要參數爲 w:
14  * ?
15  * ?
16  *
17  * 目標函數:y=w0*x0+w1*x1;
18  *
19  * */
20 #include<stdio.h>
21 #include <stdlib.h>
22 int main()
23 {
24     double matrix[4][2]={{1,4},{2,5},{5,1},{4,2}};
25     double result[4]={19,26,19,20};
26     double w[2]={0,0};//初始爲零向量
27     double loss=10.0;
28     const double n = 0.01;        //步長 
29     for(int i=0;i<100&&loss>0.001;i++)
30     {
31         double error_sum=0;
32         int j=i%4;
33         { 
34             double h=0;
35             for(int k=0;k<2;k++)
36             {
37                 h+=matrix[j][k]*w[k];
38             }
39             error_sum = h - result[j];
40             for(int k=0;k<2;k++)
41             {
42                 w[k]-= n * (error_sum) * matrix[j][k];//這裏是關鍵
43             }
44          }
45         printf("%lf,%lf\n",w[0],w[1]);
46         double loss=0;
47         for(int j=0;j<4;j++)
48         {
49             double sum=0;
50             for(int k=0;k<2;k++)
51             {
52                 sum += matrix[j][k] * w[k];
53         }
54         loss += (sum - result[j]) * (sum-result[j]);
55      }
56         printf("%lf\n",loss);
57     }
58 
59     system("pause");
60     return 0;
61 }
複製代碼

 結果可以得出  w0=3,w1=4。

 1. 對於第二種場景
複製代碼
 1 /*
 2  * 基於感知機的隨機梯度下降實驗:  《統計學習方法》- p29-例2.1 
 3  * 訓練集輸入爲矩陣:
 4  * 3,3
 5  * 4,3
 6  * 1,1
 7  * 輸出結果爲(表示實例的分類):
 8  * 1 
 9  * 1
10  * -1 
11  * 需要參數爲 w:
12  * ?
13  * ?
14  *
15  * 目標函數:y = w0 * x0 + w1 * x1 + b; 
16  *
17  * */
18 #include<stdio.h>
19 #include <stdlib.h>
20 int main()
21 {
22     double x[3][2]={{3,3},{4,3},{1,1}};
23     double y[4]={1, 1, -1};
24     double w[2]={0,0};//初始爲零向量
25     double b = 0;
26     int j;
27     const double n = 1;        //步長 
28  
29     while(1)
30     {
31         for(j=0;j<3;j++)
32         {
33             if(y[j] * (w[0] * x[j][0] + w[1] * x[j][1] + b) <= 0)
34                 break; 
35         }
36         if(j < 3)
37         {
38             for(int k=0;k<2;k++)
39                 w[k] += n * y[j] * x[j][k];//這裏是關鍵
40             b += n * y[j];
41          }
42          else
43             break;
44         printf("%d :%lf,%lf %lf\n", j, w[0], w[1], b);
45         
46     }
47 
48     system("pause");
49     return 0;
50 }
複製代碼

 結果可以得出  w0=1,w1=1, b = -3 。

       

轉自:http://www.cnblogs.com/iamccme/archive/2013/05/14/3078418.html


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