您的位置:首页 > 编程语言 > C语言/C++

梯度下降法的C语言实现

2015-12-29 11:37 323 查看
<span style="font-family: Arial, Helvetica, sans-serif;">int main()</span>
{
//double matrix[4][3] = {{4,3,1},{6,8,1},{18,26,1},{55,77,1}};
//double result[4] = {7,10,55,120};
double matrix[4][3]={{1,4,1},{2,5,1},{5,1,1},{4,2,1}};
double result[4]={19,26,19,20};
double error_sum = 0;
double theta[3] = {0,0,0};  //theta的初值全部设为,从零开始

int i,temp;

for(temp=1;temp<=1000;temp++)   //这里我没有用之前别人博客上面的参考,他的代码实际上不是run了一千遍,而是run了1000/len(data)遍。
{                               //temp用来表示迭代次数,然后i表示样本的数量,每次更新temp,都要迭代一轮i
int k,j;
for(i = 0;i<3;i++)          //因为训练数据是4个 所以i从0到3
{
double h = 0;

for(k = 0;k <3;k++)     //k负责迭代的是x的维数,也就是theta的维数,之前说过了,二位数据要设置三维的维度
{
h = h + theta[k]*matrix[i][k];     //用累加和求预测函数h(x)并且记住,每次求完h算完残差之后,都要把h重新归零
}
error_sum = h - result[i];
for(k = 0;k<3;k++)
{
theta[k] = theta[k] - 0.04*error_sum*matrix[i][k]; //梯度下降的精髓,更新k个theta值,并且减去导数方向乘以x乘以学习率alpha
}

}
printf("%lf %lf %lf ",theta[0],theta[1],theta[2]);

}

}


<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">之前我设计了一个二维数组的梯度下降,发现跑原blog上面的数据,可以跑出结果,但是,问题在于,跑我自己的数据的时候,每次都会变成负无穷。</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">我心想不应该啊,都是二元线性回归,而且基本都是一个方向的,怎么可能得到负无穷</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">后来我想了下,想明白了,我这里没有考虑常数项【也就是theta 0】 结果就是没有常数项,每个theta都会互相牵制地变大变小,也就失去了梯度下降的意义。</span>


而原代码,选择的数据恰好没有常数项,所以可以运行,囧。。

大家一定要以此为戒,如果你的数据是2维的,那么你要创建一个三维的数组【矩阵】,然后在最前面(或最后面)令其为 1

最后的经验。当从两维变成三维之后,迭代收敛的次数明显变慢了,以前100次迭代就能收敛到4.0和3.0 现在迭代1000次才只能变为4.2和3.89

因为我设置的学习率是0.01,当我“武断”地把它增大到0.02时,收敛速度快了一些。增大到0.04时,又快了一些。可还是不够好

所以邹博说得对,得继续添加对alpha的自适应。才能收敛得更快一点。

多说两句,我最初理解的梯度下降是“在人类无法求得导函数的解析式的时候,不得已而去转投梯度下降法去一步步猜着求解”实际上,并不是。

而是说机器是死的,它无法像人类一样,通过求导函数,然后解导函数为零的方程,得到极值点,然后去代入。【貌似写程序也可以?待试试】

因此,只能人类手工计算出它的导数(的方向),然后让它自己沿着导数方向一步一步走,当走到某一点时,导数为零了【也就是极值点了】,每次走的步伐大小要乘以这个导数呀,既然为零了,那步伐也为零了,也就是所谓的“收敛”了

而现在,用在线性回归里,我们人类可以计算的导函数就是(h(x)-y)*xj 所以,每次乘以这个就好了

参考:
http://blog.csdn.net/achaoluo007/article/details/40622319
很奇怪的一点!!只要我设置theta的数组为double theta[2] 就会显示乱码!!不知道为什么!但是输入theta【3】就可以正确输入!!可是我明明存三个数啊 theta【2】 就可以呀!(错!theta【2】里面只能存两个数!!!0,1,!!!切记!!

上面是批梯度下降的算法,如果改成随机梯度下降呢?

批梯度下降 是把 所有样本 从1到j全部run一遍(对应着那个迭代次数下面的for循环)。而随机梯度下降法,就不用run所有的j来更新一个theta了,而是【随机地】取一个j,(可以用取余,可以用随机数),然后直接用这个j更新一次theta,

分析:假设有40000个数据,迭代1000次 那么批梯度下降运行次数:40000*1000 随机梯度下降运行次数:4*1000 下降明显
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: