TensorFlow-梯度下降
梯度下降法是一个一阶最优化算法,通常也称为最速下降法。要使用梯度下降法找到一个函数的局部极小值,必须向函数上当前点对于梯度(或者是近似梯度)的反方向的规定步长距离点进行迭代搜索。所以梯度下降法可以帮助我们求解某个函数的极小值或者最小值。对于n维问题就最优解,梯度下降法是最常用的方法之一。下面通过梯度下降法的前生今世来进行详细推导说明。
梯度下降法的前世
首先从简单的开始,看下面的一维函数:
1 | f(x) = x^3 + 2 * x - 3 |
在数学中如果我们要求f(x) = 0处的解,我们可以通过如下误差等式来求得:
1 | error = (f(x) - 0)^2 |
当error趋近于最小值时,也就是f(x) = 0处x的解,我们也可以通过图来观察:
通过这函数图,我们可以非常直观的发现,要想求得该函数的最小值,只要将x指定为函数图的最低谷。这在高中我们就已经掌握了该函数的最小值解法。我们可以通过对该函数进行求导(即斜率):
1 | derivative(x) = 6 * x^5 + 16 * x^3 - 18 * x^2 + 8 * x - 12 |
如果要得到最小值,只需令derivative(x) = 0,即x = 1。同时我们结合图与导函数可以知道:
当x < 1时,derivative < 0,斜率为负的;
当x > 1时,derivative > 0,斜率为正的;
当x 无限接近 1时,derivative也就无限=0,斜率为零。
通过上面的结论,我们可以使用如下表达式来代替x在函数中的移动
x = x - reate * derivative
当斜率为负的时候,x增大,当斜率为正的时候,x减小;因此x总是会向着低谷移动,使得error最小,从而求得 f(x) = 0处的解。其中的rate代表x逆着导数方向移动的距离,rate越大,x每次就移动的越多。反之移动的越少。
这是针对简单的函数,我们可以非常直观的求得它的导函数。为了应对复杂的函数,我们可以通过使用求导函数的定义来表达导函数:若函数f(x)在点x0处可导,那么有如下定义:
上面是都是公式推导,下面通过代码来实现,下面的代码都是使用python进行实现。
1 | >>> def f(x): |
执行上面程序,我们就能得到如下结果:
1 | x = 0.869619, f(x) = -0.603123 |
通过上面的结果,也验证了我们最初的结论。x = 1时,f(x) = 0。
所以通过该方法,只要步数足够多,就能得到非常精确的值。
梯度下降法的今生
上面是对一维函数进行求解,那么对于多维函数又要如何求呢?我们接着看下面的函数,你会发现对于多维函数也是那么的简单。
1 | f(x) = x[0] + 2 * x[1] + 4 |
同样的如果我们要求f(x) = 0处,x[0]与x[1]的值,也可以通过求error函数的最小值来间接求f(x)的解。跟一维函数唯一不同的是,要分别对x[0]与x[1]进行求导。在数学上叫做偏导数:
保持x[1]不变,对x[0]进行求导,即f(x)对x[0]的偏导数
保持x[0]不变,对x[1]进行求导,即f(x)对x[1]的偏导数
有了上面的理解基础,我们定义的gradient_descent如下:
1 | >>> def gradient_descent(x): |
rate的作用不变,唯一的区别就是分别获取最新的x[0]与x[1]。下面是整个代码:
1 | >>> def f(x): |
输出结果为:
1 | x = -0.560000,-1.120000, f(x) = 1.200000 |
细心的你可能会发现,f(x) = 0不止这一个解还可以是x = -2, -1。这是因为梯度下降法只是对当前所处的凹谷进行梯度下降求解,对于error函数并不代表只有一个f(x) = 0的凹谷。所以梯度下降法只能求得局部解,但不一定能求得全部的解。当然如果对于非常复杂的函数,能够求得局部解也是非常不错的。
tensorflow中的运用
通过上面的示例,相信对梯度下降也有了一个基本的认识。现在我们回到最开始的地方,在tensorflow中使用gradientDescent。
1 | import tensorflow as tf |
上面的是tensorflow的官网示例,上面代码定义了函数linear_model = W * x + b,其中的error函数为linear_model - y。目的是对一组x_train与y_train进行简单的训练求解W与b。为了求得这一组数据的最优解,将每一组的error相加从而得到loss,最后再对loss进行梯度下降求解最优值。
1 | optimizer = tf.train.GradientDescentOptimizer(0.01) |
在这里rate为0.01,因为这个示例也是多维函数,所以也要用到偏导数来进行逐步向最优解靠近。
1 | for i in range(1000): |
最后使用梯度下降进行循环推导,下面给出一些推导过程中的相关结果
1 | W: [-0.21999997] b: [-0.456] loss: 4.01814 |
这里就不推理验证了,如果看了上面的梯度下降的前世今生,相信能够自主的推导出来。那么我们直接看最后的结果,可以估算为W = -1.0与b = 1.0,将他们带入上面的loss得到的结果为0.0,即误差损失值最小,所以W = -1.0与b = 1.0就是x_train与y_train这组数据的最优解。