机器学习之梯度下降、批量梯度下降与随机梯度下降

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012507022/article/details/54176144

大多数的机器学习算法都涉及某种形式的优化。优化指的是改变以最小化或者最大化某个函数的任务。我们通常以最小化指代大多数优化问题。最大化可由最小化算法最小化来实现。

我们把要最小化或者最大化的函数称为目标函数或准则。当我们对其进行最小化时,我们也把它称为代价函数、损失函数或者误差函数。

注:第一二三节引用http://blog.csdn.net/wuyanyi/article/details/8003946

一.解决目标及情景假设:

当给定一些数据,输入向量已知,输出也已知,设计一个线性函数去拟合这些数据。
既然是线性函数,在此不妨设为
此时我们遇到的问题就是如何确定这两个参数,即这个向量。
既然是拟合,则拟合效果可以用误差函数:来衡量。
其中是权重二维向量,是输入二维向量,都是训练集的数据,即已知。
至于后面除于2只是为了之后的推导过程中对求导时候可以消除系数,暂时可以不管。
因为我们解决的目标是找出一个向量使得值最小,即误差最小。
其实这个问题本质上也是搜索最优解的问题,如果用暴力搜索的话,随机取每个可能的值去让机器每天每夜地跑,显然这是不可能的。

所以此时有一种搜索策略:梯度下降。

二. 梯度下降方法:

梯度其实就是高数求导方法,对这个公式针对每个维数求偏导后的向量
梯度为最陡峭上升的方向,对应的梯度下降的训练法则为:

这里的代表学习速率,决定梯度下降搜索中的步长 。
上式的是向量,即可用将该式写成分量形式为:
现在关键就使计算∂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://www.cnblogs.com/louyihang-loves-baiyan/p/5136447.html?utm_source=tuicool&utm_medium=referral
  1. 梯度下降:在梯度下降中,对于的更新,所有的样本都有贡献,也就是参与调整。其计算得到的是一个标准梯度。因而理论上来说一次更新的幅度是比较大的。如果样本不多的情况下,当然是这样收敛的速度会更快啦。
  2. 随机梯度下降:可以看到多了随机两个字,随机也就是说我用样本中的一个例子来近似我所有的样本,来调整
  3. 批量梯度下降:其实批量的梯度下降就是一种折中的方法,他用了一些小样本来近似全部的,其本质就是我1个指不定不太准,那我用个30个50个样本那比随机的要准不少了吧,而且批量的话还是非常可以反映样本的一个分布情况的。

五.BGD、SGD以及MBGD

参考:http://www.cnblogs.com/maybe2030/p/5089753.html

博客:“梯度下降法的三种形式BGD、SGD以及MBGD”将梯度下降分为:

  1. 批量梯度下降法BGD:批量梯度下降法(Batch Gradient Descent,简称BGD)是梯度下降法最原始的形式,它的具体思路是在更新每一参数时都使用所有的样本来进行更新。(对应第四节中的梯度下降)
  2. 随机梯度下降法SGD:
  3. 小批量梯度下降法MBGD:有上述的两种梯度下降法,其各自均有优缺点,那么能不能在两种方法的性能之间取得一个折衷呢?即,算法的训练过程比较快,而且也要保证最终参数训练的准确率,而这正是小批量梯度下降法(Mini-batch Gradient Descent,简称MBGD)的初衷。(对应第四节中的批量梯度下降)

其实第四、五节的分类方法相同,只不过说法不同,对于初学者容易混淆。

六、代码及实例:

/*梯度下降法的三种形式:
*梯度下降法(Gradient descent):Use all examples in each iteration
*随机梯度下降法(Stochastic gradient descent):Use 1 example in each iteration
*批量梯度下降法(Batch Gradient Descent,简称BGD):Use b examples in each iteration
*Date:2017/01/07
*author:Xiaoming
*reference:http://blog.csdn.net/pennyliang/article/details/6998517
*http://www.cnblogs.com/louyihang-loves-baiyan/p/5136447.html?utm_source=tuicool&utm_medium=referral
*/

#include "iostream"  

using namespace std;

void MyGD(float[][2],float [],float [],float,float);  //梯度下降法
void MySGD(float[][2],float [],float [],float,float); //随机梯度下降法
void MyBGD(float[][2],float [],float [],float,float); //批量梯度下降法
int main(void)  
{  
    float matrix[4][2]={{1,4},{2,5},{5,1},{4,2}};  
    float result[4]={19,26,19,20};  
    float omega[2]={2,5};                   //初始化参数omega {2,5},模型的最有参数为 {3,4} 
    float learning_rate = 0.01;  
    float loss = 1000.0;                    //set a loss big enough  
    //MyGD(matrix,result,omega,learning_rate, loss);//梯度下降法
	//MySGD(matrix,result,omega,learning_rate, loss); //随机梯度下降法
	MyBGD(matrix,result,omega,learning_rate, loss); //批量梯度下降法
	system("pause");
    return 0;  
}  
//梯度下降法***************************************************************//
void MyGD(float x[][2],float y[],float omega[],float learning_rate,float loss)
{
	  for(int i = 0;i<100&&loss>0.0001;++i)  {  //迭代次数为100 
                float error_sum = 0.0;  
                for(int j = 0;j<4;++j)  {  
                        float h = 0.0;  
                        for(int k=0;k<2;++k)  {  
                                h += x[j][k]*omega[k];  //函数拟合
                        }  
                        error_sum = y[j]-h;  //计算误差
                        for(int k=0;k<2;++k)  {  
                                omega[k] += learning_rate*(error_sum)*x[j][k]; //更新参数omega[0],omega[1] 
                        }  
                }  
                printf("*************************************\n");  
                printf("omega now: %f,%f\n",omega[0],omega[1]);  
				/*************计算损失函数****************/
                loss = 0.0;  
                for(int j = 0;j<4;++j)  {  
                        float sum=0.0;  
                        for(int k = 0;k<2;++k)  { 
                                sum += x[j][k]*omega[k];  
                        }  
                        loss += (sum-y[j])*(sum-y[j]);  
                }  
                printf("loss  now: %f\n",loss);  
        } 
}
//随机梯度下降法***************************************************************//
void MySGD(float x[][2],float y[],float omega[],float learning_rate,float loss)
{
	for(int i =0 ;i<100&&loss>0.001;++i)  {  
        float error_sum=0.0;  
        int j=i%4;  //随机取一组数据
        {  
                float h = 0.0;  
                for(int k=0;k<2;++k)  {  
                        h += x[j][k]*omega[k]; //函数拟合 
  
                }  
                error_sum = y[j]-h;  //计算误差
                for(int k=0;k<2;++k)  {  
                        omega[k] = omega[k]+0.01*(error_sum)*x[j][k];  //更新参数omega[0],omega[1] 
                }  
        }  
		printf("*************************************\n");  
        printf("omega now:%f,%f\n",omega[0],omega[1]);  
        float loss = 0.0;  
        for(int j = 0;j<4;++j)  {  
                float sum=0.0;  
                for(int k = 0;k<2;++k)  {  
                        sum += x[j][k]*omega[k];  
                }  
                loss += (sum-y[j])*(sum-y[j]);  
        }  
        printf("loss  now:%f\n",loss);  
    }  
}
//批量梯度下降法***************************************************************//
void MyBGD(float x[][2],float y[],float omega[],float learning_rate,float loss)
{
	for(int i =0 ;i<100&&loss>0.001;++i)  {  
        float error_sum=0.0;  
        int j=i%3;  //随机取一组数据
        {  
                float h = 0.0;  
                h = x[j][0]*omega[0]+x[j][1]*omega[1];    //函数拟合 
                error_sum = y[j]-h;  //计算误差
                for(int k=0;k<2;++k)  {  
                        omega[k] = omega[k]+0.01*(error_sum)*x[j][k];  //更新参数omega[0],omega[1] 
                }  
                h = x[j+1][0]*omega[0]+x[j+1][1]*omega[1];    //函数拟合 
                error_sum = y[j+1] - h;  //计算误差
                for(int k=0;k<2;++k)  {  
                        omega[k] = omega[k]+0.01*(error_sum)*x[j+1][k];  //更新参数omega[0],omega[1] 
                }  
        }  
		printf("*************************************\n");  
        printf("omega now:%f,%f\n",omega[0],omega[1]);  
        float loss = 0.0;  
        for(int j = 0;j<4;++j)  {  
                float sum=0.0;  
                for(int k = 0;k<2;++k)  {  
                        sum += x[j][k]*omega[k];  
                }  
                loss += (sum-y[j])*(sum-y[j]);  
        }  
        printf("loss  now:%f\n",loss);  
    }  
}

参考: http://blog.csdn.net/wuyanyi/article/details/8003946

http://www.cnblogs.com/louyihang-loves-baiyan/

http://blog.csdn.net/pennyliang/article/details/6998517

http://www.cnblogs.com/boqun1991/p/4063575.html

http://www.cnblogs.com/maybe2030/p/5089753.html

猜你喜欢

转载自blog.csdn.net/u012507022/article/details/54176144
今日推荐