机器学习笔记(六)--梯度下降

最近被问机器学习是怎么训练的,那么就顺便再深入理解梯度下降算法。

一、导数

           首先我们需要复习一下导数的知识。导数是什么?一个导数是描述一个函数上的一个点在自变量增大时,因变量的变化率。在这里我讨论导数的对象为二维空间上的函数。我们用极限来表达导数,当左右侧导数相等时,这个点才存在导数。

                                                      \lim_{h \to 0^{-}} \frac{f(x_{0}+h)-f(x_{0})}{h}    及      \lim_{h \to 0^{+}} \frac{f(x_{0}+h)-f(x_{0})}{h}

                                                                         \frac{df}{dx} = \lim_{h \to 0} \frac{f(x+h)-f(x)}{h}

           这里强调一下导数的方向。用一个二次函数y = x^2为例子,这个函数的导函数就是y^{'}=2x。在(- \infty, 0)区间中,y是随着x的增加而减少的,说明这时函数上的每个点都是负增长(沿x正方向),这就是为什么导函数这时y^{'}<0

二、偏导数

           将导数从二维空间推广到多维空间,产生了多元函数的导数,就是偏导数。以二元函数z=f(x,y)为例,如果只有自变量x变化,而另一个自变量y固定不变(看成常量),那么这就是x的一元函数,这个函数对x的导数就是二元函数z对于x的偏导数(对y的偏导数同理可得)。与导数相似,偏导数的方向也是对应自变量增大(座标轴正方向)的方向,在其他自变量不变的情况下表达因变量的变化率。

                                                       \frac{\partial z}{\partial x} = f_{x}(x_{0},y_{0}) = \lim_{\Delta x \to 0} \frac{f(x_{0}+\Delta x,y_{0})-f(x_{0},y_{0})}{\Delta x}

三、方向导数

           导数与偏导数反映的是函数沿座标轴方向的变化率。那么我们如何知道函数沿任意方向的变化率呢?那么这就产生了方向导数。以二元函数f(x,y)为例,在点P_{0}(x_{0},y_{0})可微分,那么函数在该点沿任意方向l的方向导数存在,其中\alpha\beta分别是方向l与x轴和y轴的夹角。这样我们就可以得到在所有自变量都发生一定改变的方向下,因变量的变化率。

                                                               \frac{\partial f}{\partial l}|_{(x_0,y_{0})} = f_x(x_{0},y_{0})cos\alpha + f_y(x_{0},y_{0})cos\beta

四、梯度

            梯度的本意是一个向量,表示某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向(此梯度的方向)变化最快,变化率最大(为该梯度的模)。换句话说,梯度就是使一个点的方向导数达到最大的方向。那么我们怎么求出某个点的梯度?我们还是以二元函数为例。

            根据方向导数的定义,我们可以知道,一个方向导数是函数的各个偏导数与对应夹角余弦值的组合。更加直观的讲,就是先将偏导数作用到各个对应基向量(单位向量),再通过类似平行四边形法则合成的向量,就是梯度的方向。可以理解为,梯度的方向更偏向偏导数更大的基方向。如图例所示,假设i方向的偏导数更大,所以红色即为梯度方向。

                                                    grad f(x_{0},y_{0}) = \nabla f(x_{0},y_{0}) = f_{x}(x_{0},y_{0})i+f_{y}(x_{0},y_{0})j

                                            

             将梯度推广到多元函数中,我们就可以得到一个向量,表示对应点的梯度。

                                                            \nabla f(x_{1},x_{2},...,x_{n}) = <\frac{\partial f}{\partial x_{1}},\frac{\partial f}{\partial x_{2}},...,\frac{\partial f}{\partial x_{n}} >

五、梯度下降

                机器学习的本质目标就是使损失函数达到全局最小,我们就可以利用函数的梯度来求解。因为梯度是一个有大小与方向的向量,所以我们直接用矩阵运算来表示这个算法。以二元函数为例,假设有原函数,即我们需要拟合的函数h,我们将函数的输入规定为x = \begin{bmatrix} 1, & x^{'}_{1}, & x^{'}_{2}\end{bmatrix}(shape=[3,1]),那么参数向量就是\Theta = \begin{bmatrix} \Theta_{0}, & \Theta_{1}, & \Theta_{2} \end{bmatrix}(shape=[3,1])。那么X = [x_{1}^{T},x_{2}^{T},...,x_{m}^{T}]就是输入的m个样本(shape=[m,3]),h(X)为拟合值(shape=[m,1]),\overrightarrow{y}为真实值(shape=[m,1])。

                                                                                   h(x) = x^{T} \Theta

                                                                                   h(X) = X \Theta

                用均方差作损失函数,这个函数的自变量是原函数的参数,因为X是已知的样本值,m是样本数。这里涉及矩阵函数求导的问题,具体方法自行查询。

                                              J(\Theta ) =\frac{1}{2m} \sum_{i=1}^{m} (h(x^{(i)}) - y^{(i)})^{2} = \frac{1}{2m}(X\Theta - \overrightarrow{y})^{T}(X\Theta - \overrightarrow{y})

                                                          \nabla J(\Theta ) = <\frac{\partial J}{\partial\Theta _{0}} , \frac{\partial J}{\partial\Theta _{1}},\frac{\partial J}{\partial\Theta _{2}}> = \frac{1}{m}X^{T}(X\Theta -\overrightarrow{y})

                                                                      \frac{\partial J}{\partial \Theta _{0}} = \frac{1}{m} \sum_{i=1}^{m}( h(x^{(i)})- y^{(i)})       

                                                                     \frac{\partial J}{\partial \Theta _{1}} = \frac{1}{m} \sum_{i=1}^{m}( h(x^{(i)})- y^{(i)}) x{'}_{1}^{(i)}     

                                                                     \frac{\partial J}{\partial \Theta _{2}} = \frac{1}{m} \sum_{i=1}^{m}( h(x^{(i)})- y^{(i)}) x{'}_{2}^{(i)}

                迭代训练开始之前,我们初始化\Theta^{0} = \begin{bmatrix} \Theta_{0}^{0} & \Theta_{1}^{0} & \Theta_{2}^{0} \end{bmatrix}^{T},有以下迭代公式。其中,\alpha就是学习率。本质上梯度还是自变量增大的方向,只是每个自变量增大的幅度不同。注意上面偏导数的写法,是h-y,这样才是当偏导数>0的时候,因变量为正增长,所以要将对应\Theta_{i}变小。

                                                                         \Theta^{n} = \Theta^{n-1} - \alpha \nabla J(\Theta ^{n-1})

六、代码实现

                在这里我用python代码模拟梯度下降是如何一步一步到达函数的全局最小值点。

import numpy as np

# y = 1 + 2x1 + 3x2
x = np.random.random_integers(1,100,[10,3])
x[:,0] = 1

theta = np.zeros([3])
theta_real = np.asarray([1,2,3])

def PartialTheta0(x,theta):
    J = 0
    for i in range(len(x)):
        J += (np.matmul(theta,x[i]) - np.matmul(theta_real,x[i]))
    return J / len(x)

def PartialTheta1(x,theta):
    J = 0
    for i in range(len(x)):
        J += ((np.matmul(theta,x[i]) - np.matmul(theta_real,x[i])) * x[i][1])
    return J / len(x)

def PartialTheta2(x,theta):
    J = 0
    for i in range(len(x)):
        J += ((np.matmul(theta, x[i]) - np.matmul(theta_real, x[i])) * x[i][2])
    return J / len(x)


for _ in range(100000):
    theta -= 0.000001 * np.asarray([PartialTheta0(x,theta),PartialTheta1(x,theta),PartialTheta2(x,theta)])
    # theta -= 0.000001 * np.matmul(x.transpose(),np.matmul(x,theta)-np.matmul(x,theta_real)) / len(x)
    print(theta)


                   通过运行输出可以看到,参数在一步步靠近真实值,说明算法是有效的。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章