參照《機器學習》這本書的第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。