梯度下降

2019-12-03  本文已影响0人  当_下

梯度下降就是从群山中山顶找一条最短的路走到山谷最低的地方。

示意图

为什么需要梯度下降算法

如果我们抛开具体场景,仅从数学抽象的角度来看:每个模型都有自己的损失函数,不管是监督式学习还是非监督式学习。损失函数包含了若干个位置的模型参数,我们就是要找到使损失函数尽可能小的参数未知模型参数。

在学习简单线性回归时,我们使用最小二乘法来求损失函数的最小值,但是这只是一个特例。在绝大多数的情况下,损失函数是很复杂的(比如逻辑回归),根本无法得到参数估计值的表达式。因此需要一种对大多数函数都适用的方法。这就引出了“梯度算法”。

梯度下降是一种基于搜索的最优化方法。梯度下降(Gradient Descent, GD)优化算法,其作用是用来对原始模型的损失函数进行优化,以便寻找到最优的参数,使得损失函数的值最小。

要找到使损失函数最小化的参数,如果纯粹靠试错搜索,比如随机选择1000个值,依次作为某个参数的值,得到1000个损失值,选择其中那个让损失值最小的值,作为最优的参数值,那这样太笨了。我们需要更聪明的算法,从损失值出发,去更新参数,且要大幅降低计算次数。

梯度下降算法作为一个聪明很多的算法,抓住了参数与损失值之间的导数,也就是能够计算梯度(gradient),通过导数告诉我们此时此刻某参数应该朝什么方向,以怎样的速度运动,能安全高效降低损失值,朝最小损失值靠拢


什么是梯度

简单地来说,多元函数的导数(derivative)就是梯度(gradient),分别对每个变量进行微分,然后用逗号分割开,梯度是用括号包括起来,说明梯度其实一个向量,我们说损失函数L的梯度为:

举例

在单变量的函数中,梯度其实就是函数的微分,代表着函数在某个给定点的切线的斜率 在多变量函数中,梯度是一个向量,向量有方向,梯度的方向就指出了函数在给定点的上升最快的方向。

梯度指向误差值增加最快的方向,导数为0(梯度为0向量)的点,就是优化问题的解。

致命问题

从理论上,它只能保证达到局部最低点,而非全局最低点。在很多复杂函数中有很多极小值点,我们使用梯度下降法只能得到局部最优解,而不能得到全局最优解。那么对应的解决方案如下:首先随机产生多个初始参数集,即多组a,b;然后分别对每个初始参数集使用梯度下降法,直到函数值收敛于某个值;最后从这些值中找出最小值,这个找到的最小值被当作函数的最小值。当然这种方式不一定能找到全局最优解,但是起码能找到较好的。

手动实现梯度下降

首先构造一个损失函数 

然后创建在-1到6的范围内构建140个点,并且求出对应的损失函数值,这样就可以画出损失函数的图形。

接下来我们就可以进行梯度下降的操作了。首先我们需要定义一个点theta作为初始值,正常应该是随机的点,但是这里先直接定为0。然后需要定义学习率eta ,也就是每次下降的步长。这样的话,点theta 每次沿着梯度的反方向移动eta距离,即:

然后循环这一下降过程,我们可以设定一个非常小的数作为阈值,如果说损失函数的差值减小到比阈值还小,我们就认为已经找到了最小值

调整学习率

首先使用学习率0.1进行观察:

使用学习率0.01进行观察:

为了避免报错,可以对原代码进行改进:

1.在计算损失函数值时捕获异常:

def lossFunction(x):

    try:

        return (x-2.5)**2-1

    except:

        return float('inf')

2.设定条件,结束死循环:

def gradient_descent(initial_theta, eta, n_iters, epsilon=1e-6):

    theta = initial_theta

    theta_history.append(theta)

    i_iters = 0

    while i_iters < n_iters:

        gradient = dLF(theta)

        last_theta = theta

        theta = theta - eta * gradient

        theta_history.append(theta)

        if(abs(lossFunction(theta) - lossFunction(last_theta)) < epsilon):

            break

        i_iters += 1


上一篇下一篇

猜你喜欢

热点阅读