- 梯度降低的场景假设
- 梯度
- 梯度降低算法的数学解释
- 梯度降低算法的实例
- 梯度降低算法的实现
- Further reading
本文将从一个下山的场景开始,先提出梯度降低算法的基本思想,进而从数学上解释梯度降低算法的原理,最后实现一个简单的梯度降低算法的实例!python
梯度降低法的基本思想能够类比为一个下山的过程。假设这样一个场景:一我的被困在山上,须要从山上下来(i.e. 找到山的最低点,也就是山谷)。但此时山上的浓雾很大,致使可视度很低。所以,下山的路径就没法肯定,他必须利用本身周围的信息去找到下山的路径。这个时候,他就能够利用梯度降低算法来帮助本身下山。具体来讲就是,以他当前的所处的位置为基准,寻找这个位置最陡峭的地方,而后朝着山的高度降低的地方走,同理,若是咱们的目标是上山,也就是爬到山顶,那么此时应该是朝着最陡峭的方向往上走。而后每走一段距离,都反复采用同一个方法,最后就能成功的抵达山谷。算法
image.pngapi
咱们同时能够假设这座山最陡峭的地方是没法经过肉眼立马观察出来的,而是须要一个复杂的工具来测量,同时,这我的此时正好拥有测量出最陡峭方向的能力。因此,此人每走一段距离,都须要一段时间来测量所在位置最陡峭的方向,这是比较耗时的。那么为了在太阳下山以前到达山底,就要尽量的减小测量方向的次数。这是一个两难的选择,若是测量的频繁,能够保证下山的方向是绝对正确的,但又很是耗时,若是测量的过少,又有偏离轨道的风险。因此须要找到一个合适的测量方向的频率,来确保下山的方向不错误,同时又不至于耗时太多!函数
梯度降低的基本过程就和下山的场景很相似。工具
首先,咱们有一个可微分的函数。这个函数就表明着一座山。咱们的目标就是找到这个函数的最小值,也就是山底。根据以前的场景假设,最快的下山的方式就是找到当前位置最陡峭的方向,而后沿着此方向向下走,对应到函数中,就是找到给定点的梯度 ,而后朝着梯度相反的方向,就能让函数值降低的最快!由于梯度的方向就是函数之变化最快的方向(在后面会详细解释)
因此,咱们重复利用这个方法,反复求取梯度,最后就能到达局部的最小值,这就相似于咱们下山的过程。而求取梯度就肯定了最陡峭的方向,也就是场景中测量方向的手段。那么为何梯度的方向就是最陡峭的方向呢?接下来,咱们从微分开始讲起学习
看待微分的意义,能够有不一样的角度,最经常使用的两种是:google
函数的变化率
几个微分的例子:spa
image.pngcode
上面的例子都是单变量的微分,当一个函数有多个变量的时候,就有了多变量的微分,即分别对每一个变量进行求微分orm
image.png
梯度实际上就是多变量微分的通常化。
下面这个例子:
image.png
咱们能够看到,梯度就是分别对每一个变量进行微分,而后用逗号分割开,梯度是用<>包括起来,说明梯度其实一个向量。
梯度是微积分中一个很重要的概念,以前提到过梯度的意义
这也就说明了为何咱们须要想方设法的求取梯度!咱们须要到达山底,就须要在每一步观测到此时最陡峭的地方,梯度就恰巧告诉了咱们这个方向。梯度的方向是函数在给定点上升最快的方向,那么梯度的反方向就是函数在给定点降低最快的方向,这正是咱们所须要的。因此咱们只要沿着梯度的方向一直走,就能走到局部的最低点!
image.png
上面咱们花了大量的篇幅介绍梯度降低算法的基本思想和场景假设,以及梯度的概念和思想。下面咱们就开始从数学上解释梯度降低算法的计算过程和思想!
image.png
此公式的意义是:J是关于Θ的一个函数,咱们当前所处的位置为Θ0点,要从这个点走到J的最小值点,也就是山底。首先咱们先肯定前进的方向,也就是梯度的反向,而后走一段距离的步长,也就是α,走完这个段步长,就到达了Θ1这个点!
image.png
下面就这个公式的几个常见的疑问:
image.png
咱们已经基本了解了梯度降低算法的计算过程,那么咱们就来看几个梯度降低算法的小实例,首先从单变量的函数开始
咱们假设有一个单变量的函数
image.png
函数的微分
image.png
初始化,起点为
image.png
学习率为
image.png
根据梯度降低的计算公式
image.png
咱们开始进行梯度降低的迭代计算过程:
image.png
如图,通过四次的运算,也就是走了四步,基本就抵达了函数的最低点,也就是山底
image.png
咱们假设有一个目标函数
image.png
如今要经过梯度降低法计算这个函数的最小值。咱们经过观察就能发现最小值其实就是 (0,0)点。可是接下来,咱们会从梯度降低算法开始一步步计算到这个最小值!
咱们假设初始的起点为:
image.png
初始的学习率为:
image.png
函数的梯度为:
image.png
进行屡次迭代:
image.png
咱们发现,已经基本靠近函数的最小值点
image.png
下面咱们将用python实现一个简单的梯度降低算法。场景是一个简单的线性回归的例子:假设如今咱们有一系列的点,以下图所示
image.png
咱们将用梯度降低法来拟合出这条直线!
首先,咱们须要定义一个代价函数,在此咱们选用均方偏差代价函数
image.png
此公示中
h 是咱们的预测函数,根据每个输入x,根据Θ 计算获得预测的y值,即
image.png
咱们能够根据代价函数看到,代价函数中的变量有两个,因此是一个多变量的梯度降低问题,求解出代价函数的梯度,也就是分别对两个变量进行微分
image.png
明确了代价函数和梯度,以及预测的函数形式。咱们就能够开始编写代码了。但在这以前,须要说明一点,就是为了方便代码的编写,咱们会将全部的公式都转换为矩阵的形式,python中计算矩阵是很是方便的,同时代码也会变得很是的简洁。
为了转换为矩阵的计算,咱们观察到预测函数的形式
image.png
咱们有两个变量,为了对这个公式进行矩阵化,咱们能够给每个点x增长一维,这一维的值固定为1,这一维将会乘到Θ0上。这样就方便咱们统一矩阵化的计算
image.png
而后咱们将代价函数和梯度转化为矩阵向量相乘的形式
image.png
首先,咱们须要定义数据集和学习率
import numpy as np # Size of the points dataset. m = 20 # Points x-coordinate and dummy value (x0, x1). X0 = np.ones((m, 1)) X1 = np.arange(1, m+1).reshape(m, 1) X = np.hstack((X0, X1)) # Points y-coordinate y = np.array([ 3, 4, 5, 5, 2, 4, 7, 8, 11, 8, 12, 11, 13, 13, 16, 17, 18, 17, 19, 21 ]).reshape(m, 1) # The Learning Rate alpha. alpha = 0.01
接下来咱们以矩阵向量的形式定义代价函数和代价函数的梯度
def error_function(theta, X, y): '''Error function J definition.''' diff = np.dot(X, theta) - y return (1./2*m) * np.dot(np.transpose(diff), diff) def gradient_function(theta, X, y): '''Gradient of the function J definition.''' diff = np.dot(X, theta) - y return (1./m) * np.dot(np.transpose(X), diff)
最后就是算法的核心部分,梯度降低迭代计算
def gradient_descent(X, y, alpha): '''Perform gradient descent.''' theta = np.array([1, 1]).reshape(2, 1) gradient = gradient_function(theta, X, y) while not np.all(np.absolute(gradient) <= 1e-5): theta = theta - alpha * gradient gradient = gradient_function(theta, X, y) return theta
当梯度小于1e-5时,说明已经进入了比较平滑的状态,相似于山谷的状态,这时候再继续迭代效果也不大了,因此这个时候能够退出循环!
完整的代码以下
import numpy as np # Size of the points dataset. m = 20 # Points x-coordinate and dummy value (x0, x1). X0 = np.ones((m, 1)) X1 = np.arange(1, m+1).reshape(m, 1) X = np.hstack((X0, X1)) # Points y-coordinate y = np.array([ 3, 4, 5, 5, 2, 4, 7, 8, 11, 8, 12, 11, 13, 13, 16, 17, 18, 17, 19, 21 ]).reshape(m, 1) # The Learning Rate alpha. alpha = 0.01 def error_function(theta, X, y): '''Error function J definition.''' diff = np.dot(X, theta) - y return (1./2*m) * np.dot(np.transpose(diff), diff) def gradient_function(theta, X, y): '''Gradient of the function J definition.''' diff = np.dot(X, theta) - y return (1./m) * np.dot(np.transpose(X), diff) def gradient_descent(X, y, alpha): '''Perform gradient descent.''' theta = np.array([1, 1]).reshape(2, 1) gradient = gradient_function(theta, X, y) while not np.all(np.absolute(gradient) <= 1e-5): theta = theta - alpha * gradient gradient = gradient_function(theta, X, y) return theta optimal = gradient_descent(X, y, alpha) print('optimal:', optimal) print('error function:', error_function(optimal, X, y)[0,0])
运行代码,计算获得的结果以下
image.png
所拟合出的直线以下
image.png
至此,咱们就基本介绍完了梯度降低法的基本思想和算法流程,而且用python实现了一个简单的梯度降低算法拟合直线的案例!
最后,咱们回到文章开头所提出的场景假设:
这个下山的人实际上就表明了反向传播算法,下山的路径其实就表明着算法中一直在寻找的参数Θ,山上当前点的最陡峭的方向实际上就是代价函数在这一点的梯度方向,场景中观测最陡峭方向所用的工具就是微分 。在下一次观测以前的时间就是有咱们算法中的学习率α所定义的。
能够看到场景假设和梯度降低算法很好的完成了对应!
做者:六尺账篷 连接:https://www.jianshu.com/p/c7e642877b0e 來源:简书 简书著做权归做者全部,任何形式的转载都请联系做者得到受权并注明出处。