因为要开始学习机器学习的课程了,现在开始更新一下机器学习的一些内容!!!
在求解机器学习算法的模型参数,即无约束优化问题时,梯度下降和最小二乘法是两个经常常用的方法。
在微分学中,对于多元函数的参数求偏导数,把求得的各个参数的偏导数以向量的形式写出来,这就是梯度。从几何意义上来讲,这就是函数变化增加最快的地方。在这里,有两种的形式即梯度下降和梯度上升,从一定意义上来讲,两者是可以相互转换的。可以用以下的一张图片来反映梯度:
在机器学习算法中,在最小化损失函数时,我们可以通过梯度下降法来一步步迭代求解,从而得到最小化的损失函数,和模型参数值。反过来,如果要求解损失函数的最大值就可以采用梯度上升法。当然,我们在求解的过程中,计算的最小值只能是局部最优解,不一定是全局最优解。
下面来讲解一下梯度下降算法的几个概念:
1、步长(学习率)(learning rate):步长决定了在梯度下降迭代的过程中,每一步沿梯度负方向前进的长度。
2、特征(feature):这个则是指的样本的输入部分。
3、假设函数(hypothesis function):在监督学习中,为了你和输入样本,而是用的假设函数,记作hθ(x)。
4、损失函数(loss function):为了评估模型的好坏,通常用损失函数来度量拟合程度。损失函数极小化,意味着拟合程度最好,对应的模型参数即为最优参数。
梯度下降算法的矩阵形式:(因为在计算机程序中,多数算法的实现都是通过矩阵计算来实现的)
1、先决条件,对于线性回归,假设函数hθ(x1,x2,...xn)=θ0+θ1x1+...+θnxn在矩阵表达式中表示为hθ(x)=Xθ,即hθ(x)为线性的,那么损失函数可以按照最小二乘法的推广形式进行构建J(θ)=(Xθ−Y)T(Xθ−Y)
2、算法参数的初始化:θ可以进行随机初始化,而epsilon作为算法终止的阈值和步长α都需要提前初始化。
3、算法过程:这一步很重要,这是参数更新的重要步骤;
(1)确定当前位置的损失函数的梯度,对于θ向量,其梯度表达式为:
(2)用步长乘以损失函数,即得到当前位置下降的距离,即
(3)确定θ向量里的每个值,梯度下降的距离都要小于epsilon,此时算法终止,而θ向量也停止更新,即为最优参数。否则,进入步骤4。
(4)更新θ向量,其更新表达式如下,更新完毕后继续转入步骤1。
损失函数对于θθ向量的偏导数计算如下:
则步骤4更新表达式应为:
如何选择合适的步长,初始化参数是一个值得思考的问题。步长太大,可能造成迭代在极小值周围震荡,从而不收敛至极小值;步长太小,则迭代过程会过于缓慢,比如在三维曲面中,有一些局部凹陷的区域,当梯度下降到这个位置,会不断的迂回,从而使得整个函数的收敛过于缓慢而增加时间复杂度。
初始值不同,获得的最小值也有可能不同,因此梯度下降求得的只是局部最小值;当然如果损失函数是凸函数则一定是最优解。由于有局部最优解的风险,需要多次用不同初始值运行算法,关键损失函数的最小值,选择损失函数最小化的初值。
另外还有一个因素就是对特征数据进行归一化,对于每个特征x求出期望和标准差,然后转化为(xi−x)/std(x),这样转化后的特征新期望为0,方差为1,可以提高迭代效率。
用Python实现的代码如下:
def gradientdecent():
x=[(1, 0., 3), (1, 1., 3), (1, 2., 3), (1, 3., 2), (1, 4., 4)]
y=[95.364, 97.217205, 75.195834, 60.105519, 49.342380]
#假设y与x呈现线性关系,即hθ(x)=θX,J(θ)=(Xθ−Y)T(Xθ−Y)
epsilon=0.00001#初始化算法阈值为0.001
theta=[0,0,0]#初始化theta为0
alpha=0.01#初始化步长为0.01
error0=0#残差基准值初始化为0
#参数更新迭代过程
while True:
for i in range(len(x)):#更新参数theta
theta[0]-=alpha*x[i][0]*(theta[0]+theta[1]*x[i][1]+theta[2]*x[i][2]-y[i])
theta[1]-=alpha*x[i][1]*(theta[0]+theta[1]*x[i][1]+theta[2]*x[i][2]-y[i])
theta[2]-=alpha*x[i][2]*(theta[0]+theta[1]*x[i][1]+theta[2]*x[i][2]-y[i])
error1=0
for j in range(len(x)):#带入真实数据,计算残差
error1+=(y[j]-(theta[0]+theta[1]*x[j][1]+theta[2]*x[j][2]))**2/2
if abs(error1-error0)<epsilon:#判断残差是否小于阈值
break#收敛,结束
else:
error0=error1#不收敛,还原残差,继续迭代
print(theta[0],theta[1],theta[2])
gradientdecent()