《機器學習》 梯度下降

參照《機器學習》這本書的第4.4.3節。

一.解決目標及情景假設:

當給定一些數據,輸入x向量已知,輸出y也已知,設計一個線性函數y=h(x)去擬合這些數據。

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

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

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

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

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


因爲我們解決的目標是找出一個向量w=(w0,w1)使得E(w)值最小,即誤差最小。

其實這個問題本質上也是搜索最優解的問題,如果用暴力搜索的話,隨機取每個可能的值去讓機器每天每夜地跑,顯然這是不可能的。
所以此時有一種搜索策略:梯度下降。


二. 梯度下降方法:

梯度其實就是高數求導方法,對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)

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

隨機梯度下降策略來改進時間。


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

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

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

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

幸運的是,猜想成立了。

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

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

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

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

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


四.代碼及實例:

直接照着別人博客代碼敲的一遍:http://blog.csdn.net/pennyliang/article/details/6998517

/*
 * 隨機梯度下降實驗:
 * 訓練集輸入爲矩陣:
 * 1,4
 * 2,5
 * 5,1
 * 4,2
 * 輸出結果爲:
 * 19
 * 26
 * 19
 * 20
 * 需要參數爲theta:
 * ?
 * ?
 *
 * 目標函數:y=theta0*x0+theta1*x1;
 *
 *
 * */
#include<stdio.h>
int main()
{
    double matrix[4][2]={{1,4},{2,5},{5,1},{4,2}};
    double result[4]={19,26,19,20};
    double theta[2]={0,0};//初始爲零向量
    double loss=10.0;
    for(int i=0;i<100&&loss>0.001;i++)
    {
        double error_sum=0;
        int j=i%4;
        {
            double h=0;
            for(int k=0;k<2;k++)
            {
                h+=matrix[j][k]*theta[k];
            }
            error_sum=result[j]-h;
             for(int k=0;k<2;k++)
             {
                 theta[k]+=0.01*(error_sum)*matrix[j][k];//這裏是關鍵
             }
         }
         printf("%lf,%lf\n",theta[0],theta[1]);
         double loss=0;
         for(int j=0;j<4;j++)
         {
             double sum=0;
             for(int k=0;k<2;k++)
             {
                 sum+=matrix[j][k]*theta[k];
             }
             loss+=(sum-result[j])*(sum-result[j]);
         }
         printf("%lf\n",loss);
     }


     return 0;
 }

結果可以得出c0=3,c1=4。


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