版权声明:本文为博主原创文章,未经博主允许不得转载。 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个指不定不太准,那我用个30个50个样本那比随机的要准不少了吧,而且批量的话还是非常可以反映样本的一个分布情况的。
五.BGD、SGD以及MBGD
参考:http://www.cnblogs.com/maybe2030/p/5089753.html
博客:“梯度下降法的三种形式BGD、SGD以及MBGD”将梯度下降分为:
- 批量梯度下降法BGD:批量梯度下降法(Batch Gradient Descent,简称BGD)是梯度下降法最原始的形式,它的具体思路是在更新每一参数时都使用所有的样本来进行更新。(对应第四节中的梯度下降)
- 随机梯度下降法SGD:
- 小批量梯度下降法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