在谈论梯度下降算法之前,先来看看中学时候怎么求一个二次函数的最小值。
例如,现在定义如下函数:
f=x^2-x
在中学时,我们会先对其求其导数:f’=2x-1
令f’=0即可求出该函数在x=1/2时取得最小值,然而,在程序中,该怎么求呢?
首先,可以定义x以如下的方式来迭代x的值:
x=x-rate×k
在这里,rate是x值下降的速率,也可以是讲是x值减少或增加的大小,该值是人为定义的,k值是代表该点的导数,之所以rate前的符号是减号,是因为当k值为正时,x的值会减少,在这时函数是递增的,所以函数值会随着x的减少而减少,反之则刚好相反,这就保证了函数值是一直随着x值的改变而减少,从而达到收敛,可以取得最小值,而要注意的是,如果f是多维函数,那么可能是取到一个极小值而不是最小值。
而关于为什么里面用到该点的导数,是因为导数代表着该点的变化率,确保了x下降的最大值,事实上,导数已经确定了该点是怎么变化的,也就是说导数已经确定了x在某点的变化大小了,而在导数前乘以一个rate是人为改变了x的变化,当然,rate的值不能大于1的,因为当rate的值大于1的时候,引发的后果就是函数不能达到收敛,其实,当rate小于1且不够小的时候,也有可能引发这个后果。所以在这个式子中,x的变化程度是始终小于该点的导数的,也就是说x下降的最大值是该点的导数,所以才说确保了x下降的最大值。
当函数值无限接近与某个值或者函数值处于不变的时候,便认为该函数处于收敛,已求得最小值。
下面给出求该式子最小值的c代码:
-
#include <iostream>
-
int main() {
-
double rate=
0.1;
-
double x=
4;
-
double f=
0;
-
while(
true)
-
{
-
std::
cout<<
"x="<<x<<
" f(x)="<<x*x-x<<
std::
endl;
-
x=x-rate*(
2*x
-1);
-
if((f-(x*x-x))==
0)
-
{
-
-
break;
-
}
-
f=x*x-x;
-
}
-
return
0;
-
}
运算结果为:
有了上述基础后,再来讨论梯度下降算法:
梯度下降算法(Gradient descent algorithm)
梯度下降算法事实上是求多维函数的在某一点收敛的极小值,可以用这个算法迭代出在哪个点收敛,也是求最小二乘问题的一种方法。先在脑海中想象一下,你站在一座山上,怎么找到最快下山的方法,这时你当然会朝着最陡峭的方向前进,到达一个点后,再次朝着陡峭的方向下山,从而循环这些步骤,到达山脚。事实上,这也是梯度下降算法名字的由来,如图所示。
先来熟悉下有关梯度下降算法的几个术语:
1)特征值(feature):是样本的输入部分,比如目标函数:,其中x1与x2是特征值,特征值的值是属于数据集的,而且是已知的,θ1与θ2是参数,也是要求的几个值。
2)学习速率(learning rate):是决定在梯度下降中下降的大小程度,或者长度。
3)目标函数(hypothesis function):又称假设函数,是在监督学习中,为了拟合输入样本而产生的目标函数。格式如下:
倘若有两个特征变量,那么表达式则为:。
4)样本(sample):样本是一些数据,代表着样本中第i个输入样本,则对应着样本中第i个输出样本。假如:一组数据中有房子的大小,房间的数量和房子的价钱。其中房子的价钱受前两者的影响,那么一组房子大小和房间数量即可称为一个输入样本,一个房子价钱称为输出样本,其中房子大小与房间数量为其中两个特征值。
5)损失函数(loss function):损失函数是用来评估模型好坏的,其中函数值越小代表着拟合的越好。一般用假设函数减去输出样本的方差来评估,一般表达式如下:,其中m是样本的数量,乘以二分之一是便于计算。
上面说了,求得损失函数达到最小的时候,亦或者收敛的时候,目标函数与样本拟合的很好,也便能确定其中各个θ的值。
所以只要改变各个θ的值,来达到损失函数收敛即可,但是如何改变各个θ的值来让损失函数收敛呢?而且怎么保证下降的方向与大小是正确的呢?
借鉴于上文二次函数求最小值,同理,也可以参照这么做,只不过在多维函数中是求各个θ在那点的偏导数,这样便得到了下降的方向与大小:
推导得:
而判断损失函数是否收敛,可以根据函数图像来观察,亦或者判断损失函数减少时忽略不计时即可判断它收敛。
下面给出具有一个特征值的求解代码,matlab实现:
-
theta
0=
1;
-
theta1=
1;
-
r=
0.
001;
-
t=
0;
-
while(
true)
-
t=t+
1;
-
sum1=
0;
-
sum2=
0;
-
sum=
0;
-
for i=
1
:m
-
sum1=sum1+theta
0+theta1*x(i)-y(i);
-
sum2=sum2+(theta
0+theta1*x(i)-y(i))*x(i);
-
end
-
theta
0=theta
0-r*sum1/m;
-
theta1=theta1-r*sum2/m;
-
for j=
1
:m
-
sum=sum+(theta
0+theta1*x(j)-y(j))^
2;
-
end
-
J=sum/(
2*m);
-
if(J<=
4.5)
-
break;
-
end
-
end
运算结果为:theta0= -3.3929 theta1=1.1425
给出原始数据图:
验证:
因为取值的问题,虽然有些偏差,但是可以看出,拟合的已经比较好了。
正规方程组(Normal equation)
正规方程组是梯度下降算法的矩阵形式,其表达式为:
具体推导就不推了,谈谈其中的元素,其中θ代表着θ0,θ1…..θn组成的列向量,X代表着由输入样本组成的矩阵,y指输出样本组成的列矩阵。
根据此式子可求出各参数的值,下面给出代码:
-
z=ones(m,
1);
-
x=[z,x];
-
theta=pinv(x
'*x)*x'*y;
-
disp(theta);
再次利用上次使用的数据集求出:
θ0=-3.8598 θ1=1.1930
与代数法求出的结果相比相差不大,是正确的。