回归系列之梯度下降

作者: wujustin | 来源:发表于2016-11-23 00:26 被阅读1235次

    上一篇文章中,线性回归关键问题之一:求解系数的方法梯度下降。梯度下降在数据挖掘很多算法中都有应用, 属于比较基本的数学基础方法, 本文对此算法进行基本的介绍。

    梯度下降在机器学习中的意义:
    机器学习算法会利用某个统计量来刻画目标函数的拟合情况。虽然不同的算法拥有不同的目标函数表示方法和不同的系数值,但是它们拥有一个共同的目标——即通过最优化目标函数来获取最佳参数值。而梯度下降法就是优化目标函数而求得最佳参数值的方法。

    梯度下降数学原理

    理解梯度概念之前, 先预习下几个基本概念和物理意义:

    导数

    导数定义:设函数y=f(x)在点x0的某个邻域内有定义,当自变量x在x0处有增量Δx,(x0+Δx)也在该邻域内时,相应地函数取得增量Δy=f(x0+Δx)-f(x0);如果Δy与Δx之比当Δx→0时极限存在,则称函数y=f(x)在点x0处可导,并称这个极限为函数y=f(x)在点x0处的导数记为f'(x0),也记作y'│x=x0或dy/dx│x=x0,即:

    导数公式

    导数的物理意义:表示函数值在这一点的变化率。

    偏导数

    偏导数定义(以二元函数X方向偏导数为例):
    设有二元函数z=f(x,y),点(x0,y0)是其定义域D内一点.把y固定在y0而让x在x0有增量△x,相应地偏导数函数z=f(x,y)有增量(称为对x的偏增量)△z=f(x0+△x,y0)-f(x0,y0)。如果△z与△x之比当△x→0时的极限存在,那么此极限值称为函数z=f(x,y)在(x0,y0)处对x的偏导数(partial derivative)。记作f'x(x0,y0)。


    在X方向的偏导数

    如上图所示:偏导数表示固定面上一点M0(x0, y0, z0)对x轴的切线斜率;
    偏导数的物理意义:函数沿坐标轴正方向的变化率。

    方向导数

    多元函数的偏导数反映了函数值沿坐标轴方向的变化率,而方向导数则是反应的函数值沿各个方向的变化率。方向导数的定义:

    方向导数定义

    方向导数的求解公式:

    方向导数的求解公式

    说明:其中a1, a2, ..., an指的是向量L与各个坐标轴的夹角。

    在了解以上几个概念之后, 正式进入本文的正题:梯度。

    梯度

    数学对梯度的定义如下:


    Paste_Image.png

    通过上面的公式, 很显然梯度与方向导数存在某种联系。通过向量的推导,很容易得到如下公式:

    方向导数与梯度的关系

    其中:L0是方向导数中向量L的单位向量


    L0向量的定义

    要这个向量的点积达到最大, 即方向导数达到最大, gradf和L0必须同方向,也就是说当L0是梯度gradf的方向时, 方向导数到达最大。因此梯度的物理意义:是函数各个方向上变化率最大的那个方向,函数沿着梯度的方向,变化率达到最大。

    梯度下降优化目标函数的原理

    在理解梯度下降的物理意义之后, 自然就能理解梯度下降在回归算法(其他机器学习算法也会用到)的作用:优化损失函数,让损失函数一直沿着最大的降低方向变化,最终找到最小损失函数(也可能是局部最小)。具体如图所示:

    Paste_Image.png

    实现回归算法损失函数的思路:每次算出损失函数的梯度(就是对每个参数进行偏导数计算),计算出每个参数的偏导数后, 在每个参数上减去相应的偏导数,得到一个新的参数值, 损失函数就得到函数值降低最快的效果。迭代过程持续到参数收敛,参数是否收敛的判断依据是:
    1、θ值变化不再明显(差值小于某给定值);
    2、用损失函数值变化不明显,训练值加上迭代的参数值观察损失函数的变化情况,直到变化不再明显;
    3、存在收敛过慢或者死循环的情况,可以强制限制迭代次数。

    下面用数学公式推导下回归算法损失函数求解参数的相关公式。损失函数如下:

    Paste_Image.png

    PS:1/2是为后续计算偏导数方便,并不影响求解损失函数的最小值。

    对一个样本点j,参数偏导数的计算公式进行推导:


    参数偏倒数的推导过程

    对有M个样本点,第J个参数就基于上面偏导数公式进行更新,其迭代的过程如下所示:


    参数的迭代公式

    公式中alpha 是步长。

    梯度下降的局限性

    通过参数最终的迭代公式以及梯度下降的实现思路可知,梯度下降公式存在如下几个问题:

    1. 计算量很大,因为每次更新theta值时都要将整个训练集的数据代入计算,该算法在训练集合非常大的情况下将会非常低效。
    2. 计算的初始值对结果影响大。如果该函数不是凸函数(凸函数得到的最终值是全局最小值), 函数得到的是局部最小值, 初始值不一样, 最小值也会不一样。如果函数没有最小值,就会陷入无限循环中。

    梯度下降的实现

    用代码实现 简单的梯度下降程序。
    利用y = 2 * x1 + (x2^2) / 2生成x_train, y_train数据, 具体的实现如下图:

    # y = 2 * x1 + (x2^2) / 2 
    alpha=0.001
    max_count = 1000000
    
    x_train = [(1.0,3.0), (2.0, 4.0), (3.0, 5.0), (5.0,9.0), (8.0, 10.0)]
    y_train = [6.6, 12.2, 18.8, 50.5, 66.3]
    
    error_end = 0.5
    
    #h(x)
    def h(x, theta0, theta1):
        #global theta0, theta1
        #print theta0, theta1, x[0], x[1]
        hx = theta0 * x[0] + theta1 * (x[1]**2)
        return hx
    
    def gradf():
        theta0 = 0.5 
        theta1 = 0.1
        data_len = len(y_train)
        cn = 0
        is_finish = False
        while True:
            for i in range(data_len):            
                det_theta = alpha * (h(x_train[i], theta0, theta1) -  y_train[i])
                theta0 = theta0 - (det_theta) * x_train[i][0]
                theta1 = theta1 - (det_theta) * x_train[i][1]
    
            error = 0.0
            for i in range(data_len):
                error = error + ((y_train[i] - h(x_train[i], theta0, theta1))**2)/2
            cn = cn + 1
            if error < error_end or cn > max_count:
                print error
                break;
    
        print "theta:%f, %f" %(theta0, theta1)
    
    if __name__=="__main__":
       gradf()
    
    

    程序运行后得到的参数:

    theta:1.682974, 0.528715

    对比函数y = 2 * x1 + (x2^2) / 2的参数: 2, 0.5。有所差异, 但还是比较接近。

    以上是最简单的批量梯度下降方法, 梯度下降还涉及alpha步长, 非凸函数的初始化参数选取问题等等, 后续文章再探讨。

    相关文章

      网友评论

        本文标题:回归系列之梯度下降

        本文链接:https://www.haomeiwen.com/subject/ibmkpttx.html