回归系列之梯度下降

作者: 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